首页 > 其他分享 >实现网络聊天室(UDP)

实现网络聊天室(UDP)

时间:2024-08-19 20:54:03浏览次数:8  
标签:node UDP struct caddr 聊天室 网络 sockfd msg sizeof

项目需求:

  1. 如果有用户登录,其他用户可以收到这个人的登录信息
  2. 如果有人发送信息,其他用户可以收到这个人的群聊信息
  3. 如果有人下线,其他用户可以收到这个人的下线信息
  4. 服务器可以发送系统信息

服务器端:

#include<myhead.h>
struct sockaddr_in serveraddr, caddr;
enum type_t //枚举
{
    Login,
    Chat,
    Quit,
};
typedef struct MSG
{
    char type;    
    char name[32];  
    char text[128]; 
} msg_t;
 
typedef struct NODE //链表
{
    struct sockaddr_in caddr;
    struct NODE *next;
} node_t;
 
node_t *create_node(void) //建头节点
{
    node_t *p = (node_t *)malloc(sizeof(node_t));
    if (p == NULL)
    {
        perror("malloc err");
        return NULL;
    }
    p->next = NULL;
    return p;
}
void do_login(int, msg_t, node_t *, struct sockaddr_in); //登录的函数
void do_chat(int, msg_t, node_t *, struct sockaddr_in);  //群聊的函数
void do_quit(int, msg_t, node_t *, struct sockaddr_in);  //退出函数
int main(int argc, char const *argv[])
{
    if (argc != 3)
    {
        printf("Usage:./a.out <port>\n");
        return -1;
    }
    //创建UDP套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        perror("socket err");
        exit(-1);
    }
    //填充服务器网络信息结构体
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(atoi(argv[2]));
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    socklen_t len = sizeof(caddr);
    //定义保存客户端网络信息的结构体
    //绑定套接字和服务器网络信息的结构体
    bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
    printf("bind ok!\n");
    msg_t msg;
    node_t *p = create_node();
    while (1)
    {
        if (recvfrom(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&caddr, &len) < 0)
        {
            perror("recvfrom err");
            return -1;
        }
        if (msg.type == Login)
        {
            strcpy(msg.text, "以上线");
            printf("ip:%s pord:%d name:%s\n", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port), msg.name);
            printf("状态:%s\n", msg.text);
            do_login(sockfd, msg, p, caddr);
        }
        else if (msg.type == Chat)
        {
            do_chat(sockfd, msg, p, caddr);
        }
        else if (msg.type == Quit)
        {
            strcpy(msg.text, "以下线");
            printf("ip:%s pord:%d name:%s\n", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port), msg.name);
            printf("状态:%s\n", msg.text);
            do_quit(sockfd, msg, p, caddr);
        }
    }
    close(sockfd);
    return 0;
}
//登录的函数
void do_login(int sockfd, msg_t msg, node_t *p, struct sockaddr_in caddr)
{
 
    sprintf(msg.text, "%s 以上线", msg.name);
    while (p->next != NULL)
    {
        p = p->next;
        sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->caddr), sizeof(p->caddr));
        //printf("%s\n",msg.text);
    }
    node_t *new = (node_t *)malloc(sizeof(node_t));
    //初始化
    new->caddr = caddr;
    new->next = NULL;
    //链接到链表尾
    p->next = new;
    return;
}
//群聊的函数
void do_chat(int sockfd, msg_t msg, node_t *p, struct sockaddr_in caddr)
{
    //遍历链表
    while (p->next != NULL)
    {
        p = p->next;
 
        if (memcmp(&(p->caddr), &caddr, sizeof(caddr)) != 0)
        {
            sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->caddr), sizeof(p->caddr));
        }
    }
    return;
}
//退出函数
 
void do_quit(int sockfd, msg_t msg, node_t *p, struct sockaddr_in caddr)
{
    sprintf(msg.text, "%s 以下线", msg.name);
    while (p->next != NULL)
    {
        if ((memcmp(&(p->next->caddr), &caddr, sizeof(caddr))) == 0)
        {
            node_t *dele = NULL;
            dele = p->next;
            p->next = dele->next;
            free(dele);
            dele = NULL;
        }
        else
        {
            p = p->next;
            sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->caddr), sizeof(p->caddr));
        }
    }
    return;
}

客户端

#include<myhead.h>
enum type_t
{
    Login,
    Chat,
    Quit,
};
typedef struct
{
    char type;      
    char name[32];  
    char text[128]; 
} msg_t;
 
int main(int argc, char const *argv[])
{
    if (argc != 3)
    {
        printf("Usage ./a.out <ip> <port>\n");
        return -1;
    }
 
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        perror("socket err");
        exit(-1);
    }
    struct sockaddr_in serveraddr;
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(atoi(argv[2]));
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    socklen_t len = sizeof(serveraddr);
    msg_t msg;
    //先执行登录操作
    printf("请登录:\n");
    msg.type = Login;
    printf("请输入用户名:");
    fgets(msg.name, 32, stdin);
    if (msg.name[strlen(msg.name) - 1] == '\n')
        msg.name[strlen(msg.name) - 1] = '\0';
    //发送登录消息
    if (sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&serveraddr, len) < 0)
    {
        perror("sendto err");
        exit(-1);
    }
    pid_t pid = fork();
    if (pid < 0)
    {
        perror("fork err");
        exit(-1);
    }
    else if (pid == 0)
    {
        while (1)
        {
            if (recvfrom(sockfd, &msg, sizeof(msg), 0, NULL, NULL) < 0)
            {
                perror("recvfrom err");
                return -1;
            }
            printf("[%s]:%s\n", msg.name, msg.text);
        }
    }
    else
    {
        while (1)
        {
            fgets(msg.text, sizeof(msg.text), stdin);
            if (msg.text[strlen(msg.text) - 1] == '\n')
                msg.text[strlen(msg.text) - 1] = '\0';
            if (strcmp(msg.text, "quit") == 0)
            {
                msg.type = Quit;
                sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&serveraddr, len);
                kill(pid, SIGKILL);
                wait(NULL);
                exit(-1);
            }
            else
            {
                msg.type = Chat;
            }
            //发送消息
            sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&serveraddr, len);
        }
    }
    close(sockfd);
    return 0;
}

标签:node,UDP,struct,caddr,聊天室,网络,sockfd,msg,sizeof
From: https://blog.csdn.net/sjrhsk_hahaha/article/details/141306634

相关文章

  • 高校爬虫可视化系统-基于python|Django|flask的高校爬虫可视化系统|大学数据抓取与展
    博主介绍:✌十余年IT大项目实战经验、在某机构培训学员上千名、专注于本行业领域✌技术范围:Java实战项目、Python实战项目、微信小程序/安卓实战项目、爬虫+大数据实战项目、Nodejs实战项目、PHP实战项目、.NET实战项目、Golang实战项目。主要内容:系统功能设计、开题报告......
  • Node-RED开源流程网络工具
    文章目录Node-RED开源流程网络工具Node-RED介绍特点和设计理念Node-RDE安装Windows安装Docker安装基础功能示列HTTP发送请求MQTT-示列TCP-示列MQTT-Modbus示列Node-RED综合示列示列Node-RED开源流程网络工具Node-RED介绍Node-RED是一个基于Node.js的开源流程......
  • 网络
    找到了一种比较严谨的证明将一次连边,看做合并节点,如下,假设连接\(5,7\)新图变成这样:然后再在新图上继续进行操作,每次删掉的边就是桥的数量将上述过程缩的点的内部形态仍然看做原树的形态,即可知上述过程可以用书中的并查集优化(集合的代表元素就是深度最浅的节点)以后树上路......
  • 什么是网络安全?网络安全防范技术包括哪些?
    一、引言在当今数字化的时代,网络已经成为人们生活和工作中不可或缺的一部分。然而,随着网络的普及和应用的广泛,网络安全问题也日益凸显。从个人隐私泄露到企业关键信息被盗,从网络欺诈到大规模的网络攻击,网络安全威胁无处不在。因此,理解网络安全的概念以及掌握网络安全防范技术......
  • tcp与udp的总结+connect阻塞+tcp三次握手、四次挥手+常见的服务器IO(发送数据+接收数
    一,TCP与UDP的基本总结TCP(传输控制协议)和UDP(用户数据报协议)是两种主要的传输层协议。TCP是面向连接的,提供可靠、顺序的传输,适用于需要高可靠性的应用,如网页浏览和文件传输。它通过重传机制和流量控制确保数据完整性。UDP是无连接的,速度快但不保证数据的可靠性和顺序,适用于对实时性......
  • YOLOv5改进 | 融合改进 | C3融合重写星辰网络之Rewrite the Stars⭐【CVPR2024】
     秋招面试专栏推荐 :深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转......
  • 网络监控加速设备:搭载CPU(海光3350) +FPGA(复旦微V7 690T )高性能网安设备
        网络加速监控设备通常是指能够监测和优化网络数据传输速度的硬件或软件系统。尤其是在处理大量数据流、数据中心、云计算等领域,对高速数据传输、性能的稳定性及较强的扩展性有特别高的要求。下面这款设备就应运而生。简介    网络监控加速设备是集协议检测......
  • Docker不同宿主机网络打通
    本方式使用dockerSwarm集群的方式创建overlay网络进行打通背景因java微服务使用nacos做配置中心,为了解决Nacos服务注册使用Docker容器内网ip问题,使用此方案前置条件1、宿主机之间需要开通端口管理端口:2377/tcp:用于管理Swarm模式集群。这是SwarmManager和Worker......
  • 【面试】阐述TCP和UDP的区别
    面试模拟场景面试官:你能阐述一下TCP和UDP的区别吗?###参考回答示例1.连接性TCP:面向连接(Connection-Oriented):TCP是一种面向连接的协议,在传输数据之前需要建立连接。在TCP通信过程中,客户端和服务器之间通过“三次握手”来建立连接,然后再进行数据传输,确保两者之间的......
  • 网络计算机的五个组成部分
    服务器服务器是在网络环境中提供计算能力并运行软件应用程序的特定IT设备,它在网络中为其他客户机(如个人计算机、智能手机、ATM机等终端设备)提供计算或者应用服务,一般来说服务器都具备承担响应服务请求、承担服务、保障服务的能力。服务器相比普通计算机具有高速的CPU运算能力;......