1.服务器端#include udp.h int main(int argc, const char *argv[]) { printf(******************************************************\n); printf(******************************************************\n); printf(************************聊天室************************\n); printf(******************************************************\n); printf(******************************************************\n); signal(SIGCHLD,handler); node_p Hcreate_H(); int sfdsocket(AF_INET,SOCK_DGRAM,0); if(sfd-1) { perror(scoket error); return -1; } // printf(socket success sfd%d\n,sfd); int reuse 1; if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, reuse, sizeof(reuse))-1) { perror(setsockopt error); return -1; } // printf(端口号快速重用成功\n); struct sockaddr_in sin; sin.sin_familyAF_INET; sin.sin_porthtons(SER_PORT); sin.sin_addr.s_addrinet_addr(SER_IP); if(bind(sfd,(struct sockaddr*)sin,sizeof(sin))-1) { perror(bind error); return -1; } // printf(bind success\n); struct sockaddr_in cin; socklen_t socklensizeof(cin); Msg recvmsg; char rbuf[128]; pid_t pid; pidfork(); if(pid0) { while(1) { memset(recvmsg,0,sizeof(recvmsg)); if(recvfrom(sfd,recvmsg,sizeof(recvmsg),0,\ (struct sockaddr*)cin,socklen)-1) { perror(recvfrom error); return -1; } switch(recvmsg.type) { case L: //向连接客户端所有用户遍历发送xx登录 //并且将用户信息添加进链表 //用户自己不需要接收自己登录信息,所以后插入 inset_usrmsg(sfd,H,recvmsg,cin); break; case C: //聊天信息将发送到除去发送用户的每一个人 sendto_chatmsg(sfd,H,recvmsg,cin); break; case Q: //用户退出信息 //遍历链表如果不是退出用户信息将其他用户退出信息发送 //若果是此用户将其用户信息从链表中删除 sendto_quitmsg(sfd,H,recvmsg,cin); break; } } exit(EXIT_SUCCESS); } else if(pid0) { //系统发送消息到所有客户端为C类消息 recvmsg.typeC; strcpy(recvmsg.usrname,系统消息); while(1) { //将信息发送到子进程由子进程转发 fgets(recvmsg.msgtext,sizeof(recvmsg.msgtext),stdin); recvmsg.msgtext[strlen(recvmsg.msgtext)-1]0; if(sendto(sfd,recvmsg,sizeof(recvmsg),0,(struct sockaddr*)sin,sizeof(sin))-1) { perror(sendto error); return -1; } // printf(ok\n); } } close(sfd); return 0; } //创建头结点 node_p create_H() { node_p H(node_p)malloc(sizeof(node)); if(NULLH) { printf(申请空间失败\n); return NULL; } H-nextNULL; return H; } //申请新节点保存客户端信息数据 node_p create_new_point(node_p H,Msg recvmsg,struct sockaddr_in cin) { node_p new(node_p)malloc(sizeof(node)); if(NULLnew) { printf(申请空间失败\n); return NULL; } //将接收到的信息结构体中的信息保存到新节点中 strcpy(new-name,recvmsg.usrname); new-cincin; new-nextH-next; H-nextnew; printf(%s:%s\n,recvmsg.usrname,recvmsg.msgtext); return new; } int inset_usrmsg(int sfd,node_p H,Msg recvmsg,struct sockaddr_in cin) { if(NULLH) { printf(入参为空\n); return -1; } //直接将 xx登录 消息发送给当前聊天室内成员 node_p pH; while(p-next!NULL) { pp-next; if(sendto(sfd,recvmsg,sizeof(recvmsg),0,(struct sockaddr*)(p-cin),sizeof(p-cin))-1) { perror(error sendto); return -1; } } node_p newcreate_new_point(H,recvmsg,cin); return 0; } int sendto_chatmsg(int sfd,node_p H,Msg recvmsg,struct sockaddr_in cin) { if(NULLH) { printf(入参为空\n); return -1; } node_p pH; //遍历整条链表如果不是发送节点用户,服务器将消息转发 while(p-next!NULL) { pp-next; if(memcmp((p-cin),cin,sizeof(cin))) { if(sendto(sfd,recvmsg,sizeof(recvmsg),0,(struct sockaddr*)(p-cin),sizeof(p-cin))-1) { perror(send sfd); return -1; } } } printf(----------------%schat---------------\n,recvmsg.usrname); return 0; } int sendto_quitmsg(int sfd,node_p H,Msg recvmsg,struct sockaddr_in cin) { if(NULLH) { printf(入参为空\n); return -1; } node_p pH; while(p-next!NULL) { //遍历节点先找到退出登录的用户节点的前一个节点 //其他节点直接转发用户突出登录信息 if(memcmp((p-next-cin),cin,sizeof(cin))) { pp-next; if(sendto(sfd,recvmsg,sizeof(recvmsg),0,(struct sockaddr*)(p-cin),sizeof(p-cin))-1) { perror(error sfd); return -1; } } else { node_p delep-next; p-nextdele-next; free(dele); dele-nextNULL; } } } void handler(int signum) { if(signumSIGCHLD) { while(waitpid(-1,NULL,WNOHANG)0); } }2.客户端#include udp.h int main(int argc, const char *argv[]) { if(argc!3) { printf(请绑定IP地址与端口号\n); return -1; } printf(***************Jion:加入聊天室*************\n); printf(***************Quit:我再想一想*************\n); char chat[32]; scanf(%s,chat); while(getchar()!10); if(chat[0]j||chat[0]J) { printf(****WELCOME****\n); } else { return 0; } int cfdsocket(AF_INET,SOCK_DGRAM,0); if(cfd-1) { perror(socket error); return -1; } // printf(socket success cfd%d\n,cfd); struct sockaddr_in cin; cin.sin_familyAF_INET; cin.sin_porthtons(atoi(argv[2])); cin.sin_addr.s_addrinet_addr(argv[1]); if(bind(cfd,(struct sockaddr*)cin,sizeof(cin))-1) { perror(bind error); return -1; } // printf(bind success\n); struct sockaddr_in sin; sin.sin_familyAF_INET; sin.sin_porthtons(SER_PORT); sin.sin_addr.s_addrinet_addr(SER_IP); //客户端运行用户登录 Msg msgsend; bzero(msgsend,sizeof(msgsend)); //printf();//提示是否登录 printf(请输入用户名:); scanf(%s,msgsend.usrname); while(getchar()!10); char name[32]; bzero(name,32); strcpy(name,msgsend.usrname); printf(登陆成功\n); printf(输入任意键清屏\n); getchar(); system(clear); strcat(msgsend.msgtext,已登陆); msgsend.typeL;//登录消息消息类型为L sendto(cfd,msgsend,sizeof(msgsend),0,\ (struct sockaddr*)sin,sizeof(sin));//向客户端发送登录信息 struct pollfd pfds[2]; pfds[0].fd0; pfds[0].eventsPOLLIN; pfds[1].fdcfd; pfds[1].eventsPOLLIN; char wbuf[128]; while(1) { int respoll(pfds,2,-1); if(res0) { printf(time out\n); return -1; } else if(res-1) { perror(poll error); return -1; } if(pfds[0].reventsPOLLIN) { //群聊信息 bzero(msgsend,sizeof(msgsend)); strcpy(msgsend.usrname,name); fgets(msgsend.msgtext,sizeof(msgsend.msgtext),stdin); msgsend.msgtext[strlen(msgsend.msgtext)-1]0; if(strcmp(msgsend.msgtext,quit)) { msgsend.typeC; sendto(cfd,msgsend,sizeof(msgsend),0,\ (struct sockaddr*)sin,sizeof(sin)); } else if(strcmp(msgsend.msgtext,quit)0) { msgsend.typeQ; strcpy(msgsend.msgtext,退出群聊); if(sendto(cfd,msgsend,sizeof(msgsend),0,\ (struct sockaddr*)sin,sizeof(sin))-1) { perror(sendto error); return -1; } close(cfd); printf(您已经退出群聊\n); break; } } else if(pfds[1].reventsPOLLIN) { //接受服务器发送的消息 //包括服务器转发的其他用户消息与系统消息 bzero(msgsend,sizeof(msgsend)); if(recvfrom(cfd,msgsend,sizeof(msgsend),0,NULL,NULL)-1) { perror(recvfrom error); return -1; } printf(%s:%s\n,msgsend.usrname,msgsend.msgtext); } } return 0; }3.头文件#ifndef __UDP_H__ #define __UDP_H__ #include myhead.h #define SER_IP 192.168.125.20 #define SER_PORT 7171 typedef struct node { char name[32]; struct sockaddr_in cin; struct node* next; }node,*node_p; typedef struct msgTyp { char type;//L.C.Q char usrname[20]; char msgtext[1024]; }Msg; node_p create_H(); node_p create_new_point(node_p H,Msg recvmsg,struct sockaddr_in cin); int inset_usrmsg(int sfd,node_p H,Msg recvmsg,struct sockaddr_in cin); int sendto_chatmsg(int sfd,node_p H,Msg recvmsg,struct sockaddr_in cin); int sendto_quitmsg(int sfd,node_p H,Msg recvmsg,struct sockaddr_in cin); void handler(int signum); #endif
UDP网络聊天室
发布时间:2026/7/10 13:57:32
1.服务器端#include udp.h int main(int argc, const char *argv[]) { printf(******************************************************\n); printf(******************************************************\n); printf(************************聊天室************************\n); printf(******************************************************\n); printf(******************************************************\n); signal(SIGCHLD,handler); node_p Hcreate_H(); int sfdsocket(AF_INET,SOCK_DGRAM,0); if(sfd-1) { perror(scoket error); return -1; } // printf(socket success sfd%d\n,sfd); int reuse 1; if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, reuse, sizeof(reuse))-1) { perror(setsockopt error); return -1; } // printf(端口号快速重用成功\n); struct sockaddr_in sin; sin.sin_familyAF_INET; sin.sin_porthtons(SER_PORT); sin.sin_addr.s_addrinet_addr(SER_IP); if(bind(sfd,(struct sockaddr*)sin,sizeof(sin))-1) { perror(bind error); return -1; } // printf(bind success\n); struct sockaddr_in cin; socklen_t socklensizeof(cin); Msg recvmsg; char rbuf[128]; pid_t pid; pidfork(); if(pid0) { while(1) { memset(recvmsg,0,sizeof(recvmsg)); if(recvfrom(sfd,recvmsg,sizeof(recvmsg),0,\ (struct sockaddr*)cin,socklen)-1) { perror(recvfrom error); return -1; } switch(recvmsg.type) { case L: //向连接客户端所有用户遍历发送xx登录 //并且将用户信息添加进链表 //用户自己不需要接收自己登录信息,所以后插入 inset_usrmsg(sfd,H,recvmsg,cin); break; case C: //聊天信息将发送到除去发送用户的每一个人 sendto_chatmsg(sfd,H,recvmsg,cin); break; case Q: //用户退出信息 //遍历链表如果不是退出用户信息将其他用户退出信息发送 //若果是此用户将其用户信息从链表中删除 sendto_quitmsg(sfd,H,recvmsg,cin); break; } } exit(EXIT_SUCCESS); } else if(pid0) { //系统发送消息到所有客户端为C类消息 recvmsg.typeC; strcpy(recvmsg.usrname,系统消息); while(1) { //将信息发送到子进程由子进程转发 fgets(recvmsg.msgtext,sizeof(recvmsg.msgtext),stdin); recvmsg.msgtext[strlen(recvmsg.msgtext)-1]0; if(sendto(sfd,recvmsg,sizeof(recvmsg),0,(struct sockaddr*)sin,sizeof(sin))-1) { perror(sendto error); return -1; } // printf(ok\n); } } close(sfd); return 0; } //创建头结点 node_p create_H() { node_p H(node_p)malloc(sizeof(node)); if(NULLH) { printf(申请空间失败\n); return NULL; } H-nextNULL; return H; } //申请新节点保存客户端信息数据 node_p create_new_point(node_p H,Msg recvmsg,struct sockaddr_in cin) { node_p new(node_p)malloc(sizeof(node)); if(NULLnew) { printf(申请空间失败\n); return NULL; } //将接收到的信息结构体中的信息保存到新节点中 strcpy(new-name,recvmsg.usrname); new-cincin; new-nextH-next; H-nextnew; printf(%s:%s\n,recvmsg.usrname,recvmsg.msgtext); return new; } int inset_usrmsg(int sfd,node_p H,Msg recvmsg,struct sockaddr_in cin) { if(NULLH) { printf(入参为空\n); return -1; } //直接将 xx登录 消息发送给当前聊天室内成员 node_p pH; while(p-next!NULL) { pp-next; if(sendto(sfd,recvmsg,sizeof(recvmsg),0,(struct sockaddr*)(p-cin),sizeof(p-cin))-1) { perror(error sendto); return -1; } } node_p newcreate_new_point(H,recvmsg,cin); return 0; } int sendto_chatmsg(int sfd,node_p H,Msg recvmsg,struct sockaddr_in cin) { if(NULLH) { printf(入参为空\n); return -1; } node_p pH; //遍历整条链表如果不是发送节点用户,服务器将消息转发 while(p-next!NULL) { pp-next; if(memcmp((p-cin),cin,sizeof(cin))) { if(sendto(sfd,recvmsg,sizeof(recvmsg),0,(struct sockaddr*)(p-cin),sizeof(p-cin))-1) { perror(send sfd); return -1; } } } printf(----------------%schat---------------\n,recvmsg.usrname); return 0; } int sendto_quitmsg(int sfd,node_p H,Msg recvmsg,struct sockaddr_in cin) { if(NULLH) { printf(入参为空\n); return -1; } node_p pH; while(p-next!NULL) { //遍历节点先找到退出登录的用户节点的前一个节点 //其他节点直接转发用户突出登录信息 if(memcmp((p-next-cin),cin,sizeof(cin))) { pp-next; if(sendto(sfd,recvmsg,sizeof(recvmsg),0,(struct sockaddr*)(p-cin),sizeof(p-cin))-1) { perror(error sfd); return -1; } } else { node_p delep-next; p-nextdele-next; free(dele); dele-nextNULL; } } } void handler(int signum) { if(signumSIGCHLD) { while(waitpid(-1,NULL,WNOHANG)0); } }2.客户端#include udp.h int main(int argc, const char *argv[]) { if(argc!3) { printf(请绑定IP地址与端口号\n); return -1; } printf(***************Jion:加入聊天室*************\n); printf(***************Quit:我再想一想*************\n); char chat[32]; scanf(%s,chat); while(getchar()!10); if(chat[0]j||chat[0]J) { printf(****WELCOME****\n); } else { return 0; } int cfdsocket(AF_INET,SOCK_DGRAM,0); if(cfd-1) { perror(socket error); return -1; } // printf(socket success cfd%d\n,cfd); struct sockaddr_in cin; cin.sin_familyAF_INET; cin.sin_porthtons(atoi(argv[2])); cin.sin_addr.s_addrinet_addr(argv[1]); if(bind(cfd,(struct sockaddr*)cin,sizeof(cin))-1) { perror(bind error); return -1; } // printf(bind success\n); struct sockaddr_in sin; sin.sin_familyAF_INET; sin.sin_porthtons(SER_PORT); sin.sin_addr.s_addrinet_addr(SER_IP); //客户端运行用户登录 Msg msgsend; bzero(msgsend,sizeof(msgsend)); //printf();//提示是否登录 printf(请输入用户名:); scanf(%s,msgsend.usrname); while(getchar()!10); char name[32]; bzero(name,32); strcpy(name,msgsend.usrname); printf(登陆成功\n); printf(输入任意键清屏\n); getchar(); system(clear); strcat(msgsend.msgtext,已登陆); msgsend.typeL;//登录消息消息类型为L sendto(cfd,msgsend,sizeof(msgsend),0,\ (struct sockaddr*)sin,sizeof(sin));//向客户端发送登录信息 struct pollfd pfds[2]; pfds[0].fd0; pfds[0].eventsPOLLIN; pfds[1].fdcfd; pfds[1].eventsPOLLIN; char wbuf[128]; while(1) { int respoll(pfds,2,-1); if(res0) { printf(time out\n); return -1; } else if(res-1) { perror(poll error); return -1; } if(pfds[0].reventsPOLLIN) { //群聊信息 bzero(msgsend,sizeof(msgsend)); strcpy(msgsend.usrname,name); fgets(msgsend.msgtext,sizeof(msgsend.msgtext),stdin); msgsend.msgtext[strlen(msgsend.msgtext)-1]0; if(strcmp(msgsend.msgtext,quit)) { msgsend.typeC; sendto(cfd,msgsend,sizeof(msgsend),0,\ (struct sockaddr*)sin,sizeof(sin)); } else if(strcmp(msgsend.msgtext,quit)0) { msgsend.typeQ; strcpy(msgsend.msgtext,退出群聊); if(sendto(cfd,msgsend,sizeof(msgsend),0,\ (struct sockaddr*)sin,sizeof(sin))-1) { perror(sendto error); return -1; } close(cfd); printf(您已经退出群聊\n); break; } } else if(pfds[1].reventsPOLLIN) { //接受服务器发送的消息 //包括服务器转发的其他用户消息与系统消息 bzero(msgsend,sizeof(msgsend)); if(recvfrom(cfd,msgsend,sizeof(msgsend),0,NULL,NULL)-1) { perror(recvfrom error); return -1; } printf(%s:%s\n,msgsend.usrname,msgsend.msgtext); } } return 0; }3.头文件#ifndef __UDP_H__ #define __UDP_H__ #include myhead.h #define SER_IP 192.168.125.20 #define SER_PORT 7171 typedef struct node { char name[32]; struct sockaddr_in cin; struct node* next; }node,*node_p; typedef struct msgTyp { char type;//L.C.Q char usrname[20]; char msgtext[1024]; }Msg; node_p create_H(); node_p create_new_point(node_p H,Msg recvmsg,struct sockaddr_in cin); int inset_usrmsg(int sfd,node_p H,Msg recvmsg,struct sockaddr_in cin); int sendto_chatmsg(int sfd,node_p H,Msg recvmsg,struct sockaddr_in cin); int sendto_quitmsg(int sfd,node_p H,Msg recvmsg,struct sockaddr_in cin); void handler(int signum); #endif