主页 > 游戏开发  > 

基于UDP的网络聊天室

基于UDP的网络聊天室

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

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

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

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

#include<myhead.h> typedef struct Node { char usrName[20];//用户名 struct sockaddr_in cin; struct Node *next; //指针 }__link; //收发信息结构体 typedef struct msgtyp { int type; char name[20]; char text[128]; }msg; int do_lodin(int sfd,__link* head,msg recv_msg,struct sockaddr_in cin) { printf("%s[%s:%d]登陆成功\n",recv_msg.name,inet_ntoa(cin.sin_addr),ntohs(cin.sin_port)); sprintf(recv_msg.text,"----%s登陆成功----",recv_msg.name); while(head->next!=NULL) { head=head->next; if(sendto(sfd,&recv_msg,sizeof(recv_msg),0,(struct sockaddr*)&(head->cin),sizeof(head->cin))==-1) { perror("sendto"); return -1; } } //添加客户到链表 __link *new=(__link*)malloc(sizeof(__link)); new->cin=cin; new->next=NULL; head->next=new; return 0; } int do_chat(int sfd,__link* head, msg recv_msg, struct sockaddr_in cin) { printf("%s[%s:%d]chat成功\n",recv_msg.name,inet_ntoa(cin.sin_addr),ntohs(cin.sin_port)); char buf[258]=""; sprintf(buf,"%s:%s",recv_msg.name,recv_msg.text); strcpy(recv_msg.text,buf); //给其他客户端发送消息 while(head->next!=NULL) { head=head->next; head->cin=cin; if(memcmp(&cin, &head->cin, sizeof(cin)) != 0) { if(sendto(sfd,&recv_msg,sizeof(recv_msg),0,(struct sockaddr*)&(head->cin),sizeof(head->cin))==-1) { perror("sendto"); return -1; } } } return 0; } int do_quit(int sfd,__link* head, msg recv_msg, struct sockaddr_in cin) { sprintf(recv_msg.text, "-----%s 已下线-----\n", recv_msg.name); while(head->next != NULL) { if(memcmp(&cin, &head->next->cin, sizeof(cin)) == 0) { //删除 __link* temp = head->next; head->next = temp->next; free(temp); } else { head = head->next; if(sendto(sfd, &recv_msg, sizeof(recv_msg),0, (struct sockaddr*)&(head->cin), sizeof(head->cin))==-1) { perror("sendto"); return -1; } } } return 0; } int main(int argc, char *argv[]) { if(argc<3) { printf("请输入ip和端口号\n"); return -1; } int sfd=socket(AF_INET,SOCK_DGRAM,0); if(sfd==-1) { perror("socket"); return -1; } int reuse=-1; if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))==-1) { perror("setsockopt"); return -1; } struct sockaddr_in sin; sin.sin_family=AF_INET; sin.sin_port=htons(atoi(argv[2])); sin.sin_addr.s_addr=inet_addr(argv[1]); if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))==-1) { perror("bind"); return -1; } //printf("bind success\n"); int res=fork(); //父进程接收消息 if(res>0) { __link *head=(__link*)malloc(sizeof(__link)); head->next=NULL; msg recv_msg; int recv_len=0; struct sockaddr_in cin; socklen_t len=sizeof(cin); while(1) { recv_len=recvfrom(sfd,&recv_msg,sizeof(recv_msg),0,(struct sockaddr*)&cin,&len); if(recv_len<0) { perror("recvfrom"); return -1; } int type=ntohl(recv_msg.type); switch(type) { case 1: { do_lodin(sfd,head,recv_msg,cin); } break; case 2: { do_chat(sfd,head,recv_msg,cin); } break; case 3: { do_quit(sfd,head,recv_msg,cin); } break; } } }else if(res==0) { //子进程,发送系统消息 msg sys_msg={htonl(1),"**system**"}; while(1) { bzero(sys_msg.text,1024); fgets(sys_msg.text,1024,stdin); sys_msg.text[strlen(sys_msg.text)-1]=0; if(sendto(sfd,&sys_msg,sizeof(sys_msg),0,(struct sockaddr*)&sin,sizeof(sin))==-1) { perror("sendto"); return -1; } } printf("系统消息发送成功\n"); } close(sfd); return 0; }

客户端代码

#include<myhead.h> #define LOGIN 1 #define CHAT 2 #define QUIT 3 #define ERR_LOG(msg) do{\ printf("%d %s %s \n", __LINE__, __func__, __FILE__);\ perror(msg);\ }while(0) //收发信息的结构体 typedef struct { int type; char name[20]; char text[128] ; }MSG; typedef void (*sighandler_t)(int); int do_chat(int sfd, MSG msg, struct sockaddr_in sin) { while(1) { //从终端获取聊天信息 bzero(msg.text, 128); fgets(msg.text, 128,stdin); msg.text[strlen(msg.text)-1] = 0; if(strncasecmp(msg.text, "QUIT",4) == 0) { msg.type = htonl(QUIT); } else { msg.type = htonl(CHAT); } //发送 if(sendto(sfd, &msg, sizeof(msg), 0, (void*)&sin, sizeof(sin)) < 0) { ERR_LOG("sendto"); return -1; } //如果是退出信息,则客户端要退出 if(msg.type == htonl(QUIT)) { exit(0); //退出子进程; } } } int do_recv(int sfd) { MSG rcv_msg ; while(1) { if(recvfrom(sfd, &rcv_msg, sizeof(rcv_msg), 0, NULL, NULL) < 0) { perror("recvfrom"); return -1; } printf("%s\n",rcv_msg.text); } } void handler(int sig) { //回收子进程资源并退出 while(waitpid(-1,NULL, WNOHANG)>0); exit(0); } int main(int argc, char *argv[]) { if(argc < 3) { printf("请输入 ip 和端口号\n"); return -1; } sighandler_t s = signal(SIGCHLD, handler); if(s == SIG_ERR) { ERR_LOG("signal"); return -1; } int sfd = socket(AF_INET, SOCK_DGRAM, 0); if(sfd < 0) { perror("socket"); return -1; } //2.填充服务器ip和端口号 struct sockaddr_in sin; sin.sin_family=AF_INET; sin.sin_port=htons(atoi(argv[2])); sin.sin_addr.s_addr=inet_addr(argv[1]); socklen_t addrlen = sizeof(sin); //登录协议 MSG msg ; msg.type = htonl(1); printf("请输入姓名>>>"); fgets(msg.name, 20, stdin); msg.name[strlen(msg.name)-1] = 0; if(sendto(sfd, &msg, sizeof(msg), 0, (void*)&sin, sizeof(sin)) < 0) { ERR_LOG("sendto"); return -1; } pid_t pid = fork(); if(pid > 0) { //父进程获取信息 do_recv(sfd); } else if(0 == pid) { //子进程发送信息 do_chat(sfd, msg, sin); } //4.关闭套接字 close(sfd); return 0; }

效果

标签:

基于UDP的网络聊天室由讯客互联游戏开发栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“基于UDP的网络聊天室