基于UDP的网络聊天室

代码:

服务器端:

复制代码
#include <myhead.h>
#define SER_IP "192.168.125.151"
#define SER_PORT 9999
typedef struct Msg
{
    char user[32];   //用户名
    int type;        //执行操作1.登录、2.发消息、0.退出
    char text[1024]; //消息内容
} msg_t;
typedef struct List
{
    struct sockaddr_in cin; //客户端的网络信息结构体
    struct List *next;      //链表指针,指向下一个
} * list;
 
struct sockaddr_in cin;
//创建头节点
list list_create()
{
    list p = (list)malloc(sizeof(struct List));
    if (p == NULL)
    {
        perror("create list error");
    }
    p->next = NULL;
    p = NULL;
}
//线程函数事件 向所有客户端发送消息
void *task(void *arg)
{
    int *sockfd = (int *)arg;
    msg_t msg;
    strcpy(msg.user, "*system*");
    while (1)
    {
        scanf("%s", msg.text);
        getchar();
        if (strncmp(msg.text, "quit", 4) == 0)
        {
            exit(0);
        }
        sendto(*sockfd, msg.text, sizeof(msg), 0, (struct sockaddr *)&cin, sizeof(cin));
    }
}
//登录事件处理
void login(int sockfd, msg_t msg, list p, struct sockaddr_in cin)
{
    //新客户端插入链表
    list new = NULL;
    new = (list)malloc(sizeof(struct List));
    sprintf(msg.text, "login");
    while (p->next != NULL)
    {
        //发送给的其他客户端登录消息
        p = p->next;
        sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->cin), sizeof(p->cin));
        printf("[%s:%d]:%s login\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), msg.user);
    }
    //新节点的数据域填充新客户端地址结构体,尾插
    new->cin = cin;
    p->next = new;
    new->next = NULL;
}
//接收客户端消息事件处理
void chatmsg(int sockfd, msg_t msg, list p, struct sockaddr_in cin)
{
    //将客户端发来的消息发送给其他客户端
    while (p->next != NULL)
    {
        p = p->next;
        sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->cin), sizeof(p->cin));
    }
}
//客户端退出消息事件处理
void quit(int sockfd, msg_t msg, list p, struct sockaddr_in cin)
{
    list del = NULL;
    sprintf(msg.text, "%s out", msg.user);
    while (p->next != NULL)
    {
        //遍历链表找到要退出的客户端地址结构体的前一个
        if (memcmp(&(p->next->cin), &cin, sizeof(cin)) == 0)
        {
            del = p->next;
            p->next = del->next;
            free(del);
            del = NULL;
        }
        else
        {
            p = p->next;
            sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->cin), sizeof(p->cin));
        }
    }
}
int main(int argc, char const *argv[])
{
    msg_t msg;
    //创建套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1)
    {
        perror("socket error");
        return -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);
    //绑定服务器
    if (bind(sockfd, (struct sockaddr *)&sin, sizeof(sin)) == -1)
    {
        perror("bind error");
        return -1;
    }
    //创建客户端地址结构体
    struct sockaddr_in cin;
    //获取客户端地址结构体大小
    socklen_t socklen = sizeof(cin);
    //创建链表节点
    list p = list_create();
    //创建线程
    pthread_t tid;
    if (pthread_create(&tid, NULL, task, &sockfd) == -1)
    {
        printf("pthread_create error\n");
        return -1;
    }
    //分离线程
    pthread_detach(tid);
    //接收客户端消息
    while (1)
    {
 
        //接收客户端发来的消息,返回消息字符个数
        int res = recvfrom(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&cin, &socklen);
        if (res < 0)
        {
            perror("recvfrom error");
            return -1;
        }
        //判断三种客户端状态 1登录 2消息 0退出
        if (msg.type == 1)
        {
            login(sockfd, msg, p, cin);
        }
        else if (msg.type == 2)
        {
            chatmsg(sockfd, msg, p, cin);
        }
        else if (msg.type == 0)
        {
            printf("[%s:%d] %s out\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), msg.user);
            quit(sockfd, msg, p, cin);
        }
    }
    //关闭套接字
    close(sockfd);
    return 0;
}

客户端:

复制代码
#include <myhead.h>
#define SER_IP "192.168.125.151"
#define SER_PORT 9999
typedef struct Msg
{
    char user[32];   //用户名
    int type;        //执行操作1.登录、2.发消息、0.退出
    char text[1024]; //消息内容
} msg_t;
int main(int argc, char const *argv[])
{
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1)
    {
        perror("sock error");
        return -1;
    }
    msg_t msg;
    struct sockaddr_in cin;
    cin.sin_family = AF_INET;
    cin.sin_addr.s_addr = inet_addr(SER_IP);
    cin.sin_port = htons(SER_PORT);
    socklen_t socklen = sizeof(cin);
    char buf[128] = "";
 
    msg.type = 1;
    printf("please imput your name:");
    scanf("%s", msg.user);
    getchar();
 
    sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&cin, socklen);
 
    pid_t pid = fork();
    if (pid < 0)
    {
        perror("fork error");
        return -1;
    }
    else if (pid == 0) //子进程循环发送消息
    {
        while (1)
        {
            printf("---------------------\n");
            scanf("%s", msg.text);
            getchar();
            if (strncmp(msg.text, "quit", 4) == 0)
            {
                msg.type = 0;
                sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&cin, socklen);
                kill(pid, SIGINT);
                exit(0);
                wait(NULL);
            }
            else
            {
                msg.type = 2;
            }
            sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&cin, socklen);
        }
    }
    else //父进程循环接受消息
    {
        int res;
        while (1)
        {
            res = recv(sockfd, &msg, sizeof(msg), 0);
            if (res == -1)
            {
                perror("recv error");
                return -1;
            }
            printf("[%s]:%s\n", msg.user, msg.text);
        }
        wait(NULL);
    }
    close(sockfd);
    return 0;
}
相关推荐
XTIOT66611 小时前
零部件 DPM 码扫码枪生产厂家:工业 DPM 设备多工位组网与 MES/ERP 数据集成方案
网络·单片机·嵌入式硬件·物联网·计算机视觉
夜雪一千11 小时前
TCP协议简介
网络·网络协议·tcp/ip
清欢渡---11 小时前
防火墙---安全策略配置
网络·防火墙·防御保护
TlSfoward12 小时前
如何用 TLS 与 HTTP 指标降低误伤 TLSFOWARD抓包工具
网络·网络协议·http
跨境小陈12 小时前
2026 年如何使用 Python 抓取 Reddit 数据
开发语言·网络·python
念恒1230612 小时前
Socket编程UDP(中)
linux·网络协议·udp
汤愈韬13 小时前
关于OSPF中一类、二类、三类LSA的一些思考
网络·网络协议
柒号华仔14 小时前
一文讲透5G RedCap
网络协议·5g·信息与通信
Flandern111114 小时前
HTTPS(TLS 1.3)完整流程
数据库·网络协议·计算机网络·https
我送炭你添花14 小时前
HART协议详解:00 为什么工业世界仍然需要HART?
网络·机器人·自动化·智能工厂