坐牢第二十七天(聊天室)

基于UDP的网络聊天室

一.项目需求:

1.如果有用户登录,其他用户可以收到这个人的登录信息

2.如果有人发送信息,其他用户可以收到这个人的群聊信息

3.如果有人下线,其他用户可以收到这个人的下线信息

4.服务器可以发送系统信息

二.代码 

udp.h

#ifndef UDP_H
#define UDP_H
#include <myhead.h>
#define SER_PORT 8888           // 服务器端口号
#define SER_IP "192.168.0.105" // 服务器ip地址
#define CLI_PORT 5555          // 客户端端口号
#define CLI_IP "192.168.0.105" // 客户端地址
//枚举
enum type_t
{
    Login,
    Chat,
    Quit,
};
typedef struct MSG
{
    char type;//Login名字  Chat内容 Quit退出  //内容编号
    char name[32];//名字
    char text[128];//内容
}msg_t;
typedef struct NODE//链表
{
    struct sockaddr_in cin;
    struct NODE *next;
}Node,*Nodeptr;
//创建头节点函数
Nodeptr create();
//登录的函数
//功能:
//1.将新登录的用户转发给所有已经登录的用户(遍历链表发送谁登录的消息)
//2.创建新节点来保存新登录用户的信息,链接到链表尾就可以
void do_login(int sockfd,msg_t msg,Nodeptr p,struct sockaddr_in cin);
//群聊的函数
//功能:将客户端发来的聊天内容转发给所有已登录的用户,除了发送聊天内容的用户以外
void do_chat(int sockfd,msg_t msg,Nodeptr p,struct sockaddr_in cin);
//退出函数
//功能:
//1.将谁退出的消息转发给i所有用户
//2.将链表中保存这个推出的用户信息的节点删除
void do_quit(int sockfd,msg_t msg,Nodeptr p,struct sockaddr_in cin);
#endif 

udp.c

#include "udp.h"
// 定义创建头节点函数
Nodeptr create()
{
    Nodeptr p = (Nodeptr)malloc(sizeof(Node));
    if (p == NULL)
    {
        perror("malloc error");
        return NULL;
    }
    p->next = NULL;
    return p;
}
// 定义登录的函数
void do_login(int sockfd, msg_t msg, Nodeptr p, struct sockaddr_in cin)
{
    sprintf(msg.text, "%s 以上线", msg.name);
    while (p->next != NULL)
    {
        p = p->next;
        sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->cin), sizeof(p->cin));
    }
    Nodeptr new = (Nodeptr)malloc(sizeof(Node));
    // 初始化
    new->cin = cin;
    new->next = NULL;
    // 链接到链表尾
    p->next = new;
    return;
}
// 定义群聊的函数
void do_chat(int sockfd, msg_t msg, Nodeptr p, struct sockaddr_in cin)
{
    // 遍历链表
    while (p->next != NULL)
    {
        p = p->next;

        if (memcmp(&(p->cin), &cin,sizeof(cin))!= 0)
        {
            sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->cin), sizeof(p->cin));
        }
    }
    return;
}
// 定义退出函数
void do_quit(int sockfd, msg_t msg, Nodeptr p, struct sockaddr_in cin)
{
    sprintf(msg.text, "%s 以下线", msg.name);
    while (p->next != NULL)
    {
        if (memcmp(&(p->cin), &cin,sizeof(cin)) == 0)
        {
            Nodeptr q = NULL;
            q = p->next;
            p->next = q->next;
            free(q);
            q = NULL;
        }
        else
        {
            p = p->next;
            sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->cin), sizeof(p->cin));
        }
    }
    return;
}

sen.c

// 服务器
#include "udp.h"
int main(int argc, char const *argv[])
{
    // 创建UDP套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        perror("socket error");
        exit(-1);
    }    
    // 填充服务器网络信息结构体
    //定义服务器结构体 
    struct sockaddr_in sin;
    sin.sin_family=AF_INET;
    sin.sin_port = htons(SER_PORT);
    sin.sin_addr.s_addr = inet_addr(SER_IP);
   
    // 定义保存客户端网络信息的结构体
    struct sockaddr_in cin;
    cin.sin_family = AF_INET;
    cin.sin_port = htons(CLI_PORT);
    cin.sin_addr.s_addr = inet_addr(CLI_IP);
    socklen_t len = sizeof(cin);
    // 绑定套接字和服务器网络信息的结构体
    bind(sockfd, (struct sockaddr *)&sin, sizeof(sin));
    printf("绑定成功!\n");
    msg_t msg;
    Nodeptr p = create();
    char s[20]="";
    while (1)
    {
        if (recvfrom(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&cin, &len) < 0)
        {
            perror("recvfrom error");
            return -1;
        }
        if (msg.type == Login)
        {
            strcpy(msg.text, "以上线");
            printf("ip:%s pord:%d name:%s\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), msg.name);
            printf("状态:%s\n", msg.text);
            //调用登录函数
            do_login(sockfd, msg, p, cin);
        }
        else if (msg.type == Chat)
        {
            //调用群聊函数
            do_chat(sockfd, msg, p, cin);
        }
        else if (msg.type == Quit)
        {
            strcpy(msg.text, "以下线");
            printf("ip:%s pord:%d name:%s\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), msg.name);
            printf("状态:%s\n", msg.text);
            //调用退出函数
            do_quit(sockfd, msg, p, cin);
        }
    }
    close(sockfd);
    return 0;
}

rec.c

// 客户端
#include "udp.h"
int main(int argc, char const *argv[])
{
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        perror("socket error");
        exit(-1);
    }
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(SER_PORT);
    sin.sin_addr.s_addr = inet_addr(SER_IP);
    socklen_t len = sizeof(sin);
    msg_t msg;
    // 先执行登录操作
    printf("请登录:\n");
    msg.type = Login;
    printf("请输入用户名:");
    fgets(msg.name, 32, stdin);
    msg.name[strlen(msg.name) - 1] = 0;
    // 发送登录消息
    if (sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&sin, len) < 0)
    {
        perror("sendto err");
        exit(-1);
    }
    //创建多进程
    pid_t pid = fork();
    if (pid < 0)
    {
        perror("fork error");
        exit(-1);
    }
    else if (pid == 0)
    {
        while (1)
        {
            if (recvfrom(sockfd, &msg, sizeof(msg), 0, NULL, NULL) < 0)
            {
                perror("recvfrom error");
                return -1;
            }
            printf("[%s]:%s\n", msg.name, msg.text);
        }
    }
    else
    {
        while (1)
        {
            fgets(msg.text, sizeof(msg.text), stdin);
            msg.text[strlen(msg.text) - 1] = 0;
            if (strcmp(msg.text, "quit") == 0)
            {
                msg.type = Quit;
                sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&sin, len);
                kill(pid, SIGKILL);
                wait(NULL);
                exit(EXIT_SUCCESS);
            }
            else
            {
                msg.type = Chat;
            }
            // 发送消息
            sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&sin, len);
        }
    }
    close(sockfd);
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/870867.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

海外媒体投稿:5个软文代发推广入门技巧

1. 软文代发概述 软文代发是一种通过第三方渠道发布软文的推广方式。它可以帮助小白快速上手推广&#xff0c;提高品牌知名度、产品销量等。软文代发不仅能够吸引更多的目标用户&#xff0c;还能提高网站的流量和转化率&#xff0c;从而带来更多的商机。 2. 明确目标受众和需求…

精武杯的部分复现

标红的为答案 计算机手机部分 1、请综合分析计算机和⼿机检材&#xff0c;计算机最近⼀次登录的账户名是&#xff1f;admin 2.请综合分析计算机和⼿机检材&#xff0c;计算机最近⼀次插⼊的USB存储设备串号是?S3JKNX0JA05097Y 3.请综合分析计算机和⼿机检材&#xff0c;谢弘…

企业文件防泄密解决方案有哪些?2024年10款文件加密软件排行榜

在当今数字化时代&#xff0c;企业文件的安全性成为了企业运营中的关键一环。防止敏感信息泄露&#xff0c;不仅关乎企业的商业机密&#xff0c;还直接影响到企业的信誉和竞争力。因此&#xff0c;采用有效的文件防泄密解决方案变得尤为重要。2024年&#xff0c;市场上涌现了众…

hyper-v连接显卡,hyper-v使用显卡能力、Hyper-V显卡虚拟化VMGpu设置

hyper-v连接显卡&#xff0c;hyper-v使用显卡能力、Hyper-V显卡虚拟化VMGpu设置 现在越来越多的软件在使用时&#xff0c;都会调用GPU获得更好的使用效果。如&#xff1a;浏览器的硬件加速模式。由于Nvidia和AMD都屏蔽了家用显卡虚拟化技术&#xff0c;常用的虚拟机也无法对显卡…

ftp搭建yum仓库

准备两台Linux虚拟机&#xff0c;关闭防火墙和核心防护。 实验步骤&#xff1a; 在ftp服务端安装vsftpd 在/var/ftp目录下创建目录centos&#xff0c;并将镜像挂载到该目录下 开启vsftpd服务 在客户机上设置yum仓库配置 清理缓存&#xff0c;检查yum仓库配置 安装一个程序&am…

YUM和NFS

文章目录 yum软件仓库的提供方式RPM软件包的来源Linux系统各家厂商用的安装源命令---yum 配置本地yum源具体操作 搭建ftp yum仓库环境具体操作实操环境服务端一、安装 vsftpd服务二、创建一个文件&#xff0c;并且挂载三、开启服务四、查看挂载 客户端五、备份六、搭建ftp yum仓…

python爬虫爬取某图书网页实例

文章目录 导入相应的库正确地设置代码的基础部分设置循环遍历遍历URL保存图片和文档全部代码即详细注释 下面是通过requests库来对ajax页面进行爬取的案例&#xff0c;与正常页面不同&#xff0c;这里我们获取url的方式也会不同&#xff0c;这里我们通过爬取一个简单的ajax小说…

并行程序设计基础——非阻塞通信实现Jacobi迭代

目录 一、非阻塞通信实现Jacobi迭代 二、重复非阻塞通信 1、标准模式-MPI_SEND_INIT 2、同步模式-MPI_SSEND_INIT 3、缓存模式-MPI_BSEND_INIT 4、就绪模式-MPI_RSEND_INIT 5、MPI_RECV_INIT 三、重复非阻塞通信实现Jacobi迭代 上一节我们介绍了MPI非阻塞通信的…

Unity的地编系统

目录 基础操作与流程&#xff1a; 模型和材质制作&#xff1a; 六边形地图系统&#xff1a; 无缝大地图实现&#xff1a; 插件与扩展功能&#xff1a; 导航与寻路系统&#xff1a; 案例教学与视频教程&#xff1a; 技术问答与社区支持&#xff1a; Unity地编系统中如何…

云原生系列 - Nginx(基础篇)

前言 学习视频&#xff1a;尚硅谷Nginx教程&#xff08;亿级流量nginx架构设计&#xff09;本内容仅用于个人学习笔记&#xff0c;如有侵扰&#xff0c;联系删学习文档&#xff1a; 云原生系列 - Nginx(基础篇) 1、简介 1.1、背景介绍 Nginx(enginex)是一个高性能的HTTP和…

javaer快速入门 goweb框架 gin

gin 入门 前置条件 安装环境 配置代理 # 配置 GOPROXY 环境变量&#xff0c;以下三选一# 1. 七牛 CDN go env -w GOPROXYhttps://goproxy.cn,direct# 2. 阿里云 go env -w GOPROXYhttps://mirrors.aliyun.com/goproxy/,direct# 3. 官方 go env -w GOPROXYhttps://goproxy.…

阻抗控制中的dynamic movement primitives(DMP) model

在阻抗控制中&#xff0c;Dynamic Movement Primitives (DMP) 模型被用于实现一种高度灵活且可泛化的轨迹模仿学习方法。DMP模型由美国南加州大学&#xff08;University of Southern California&#xff09;的Stefan Schaal教授团队于2002年提出&#xff0c;它通过将动态系统建…

FreeRTOS 快速入门(三)之任务管理

目录 一、任务创建与删除1、什么是任务2、创建任务3、任务的删除 二、任务优先级和 Tick1、任务优先级2、Tick3、 修改优先级 三、任务状态1、阻塞状态(Blocked)2、暂停状态(Suspended)3、就绪状态(Ready)4、状态转换 四、Delay 函数五、空闲任务及其钩子函数1、介绍2、使用钩子…

议题揭晓 | 8 月 24 日,deepin 23 Release Party 暨武汉 LUG 等你来!

查看原文 Hi&#xff0c;Linuxer&#xff01; 历经三年的精心打磨和无数次的迭代测试&#xff0c;deepin 23 已正式发布&#xff0c;不少伙伴已上手体验&#xff0c;我们也收到了诸多积极反馈。 为了庆祝这一里程碑&#xff0c;本次武汉LUG暨deepin 23 线下发布活动&#xf…

二叉树(四)

一、二叉树的性质 二、练习 1.某二叉树共有399个节点&#xff0c;其中有199个度为2的节点&#xff0c;则二叉树中的叶子节点数为&#xff08; &#xff09;。 A.不存在这样的树 B.200 C.198 D.199 答案&#xff1a;B 参考二叉树的性质第三条 2.在具有2…

单位严禁非授权设备接入网络,此方案高效防护,安心无忧!

MAC与IP地址绑定策略 MAC地址&#xff08;媒体访问控制地址&#xff09;与IP地址&#xff08;互联网协议地址&#xff09;作为计算机网络中的两大关键标识符&#xff0c;分别在数据链路层与网络层各司其职。将二者绑定&#xff0c;是网络安全领域的一项常用手段&#xff0c;旨…

零基础5分钟上手亚马逊云科技核心云开发知识 - 网络基础

简介&#xff1a; 欢迎来到小李哥全新亚马逊云科技AWS云计算知识学习系列&#xff0c;适用于任何无云计算或者亚马逊云科技技术背景的开发者&#xff0c;通过这篇文章大家零基础5分钟就能完全学会亚马逊云科技一个经典的服务开发架构方案。 我会每天介绍一个基于亚马逊云科技…

Spring发送邮件性能优化?如何集成发邮件?

Spring发送邮件安全性探讨&#xff01;Spring发送邮件功能有哪些&#xff1f; 邮件发送的性能逐渐成为影响用户体验的重要因素之一。AokSend将探讨如何在Spring框架中进行Spring发送邮件的性能优化&#xff0c;确保系统能够高效、稳定地处理大量邮件请求。 Spring发送邮件&am…

Chat App 项目之解析(三)

Chat App 项目介绍与解析&#xff08;一&#xff09;-CSDN博客文章浏览阅读76次。Chat App 是一个实时聊天应用程序&#xff0c;旨在为用户提供一个简单、直观的聊天平台。该应用程序不仅支持普通用户的注册和登录&#xff0c;还提供了管理员登录功能&#xff0c;以便管理员可以…

《黑神话:悟空》媒体评分解禁 M站均分82

《黑神话&#xff1a;悟空》媒体评分现已解禁&#xff0c;截止发稿时&#xff0c;M站共有43家媒体评测&#xff0c;均分为82分。 部分媒体评测&#xff1a; God is a Geek 100&#xff1a; 毫无疑问&#xff0c;《黑神话&#xff1a;悟空》是今年最好的动作游戏之一&#xff…