日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

网络编程 : 基于UDP的网络群聊聊天室

發布時間:2024/8/1 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 网络编程 : 基于UDP的网络群聊聊天室 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、UDP網絡編程:

1.1 流程

服務器流程:

創建用戶數據報套接字

填充服務器的網絡信息結構體

綁定套接字與服務器網絡信息結構體

收發數據

關閉套接字

客戶端流程:

創建用戶數據報套接字

填充服務器的網絡信息結構體

收發數據

關閉套接字

二、基于UDP的網絡群聊聊天室? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

?2.1 功能:

有新用戶登錄,其他在線的用戶可以收到登錄信息

有用戶群聊,其他在線的用戶可以收到群聊信息

有用戶退出,其他在線的用戶可以收到退出信息

服務器可以發送系統信息

提示:

客戶端登錄之后,為了實現一邊發送數據一邊接收數據,可以使用多進程或者多線程

服務器既可以發送系統信息,又可以接收客戶端信息并處理,可以使用多進程或者多線程

服務器需要給多個用戶發送數據,所以需要保存每一個用戶的信息,使用鏈表來保存

數據傳輸的時候要定義結構體,結構體中包含操作碼、用戶名以及數據

2.2? 流程圖

?

?2.3 代碼實現

?頭文件:dup.h

#ifndef __UDP_H__ #define __UDP_H__#include <stdio.h> #include <stdlib.h> #include <string.h> #include<sys/socket.h> #include<sys/types.h> #include<unistd.h> #include<netinet/in.h> #include<netinet/ip.h> #include<arpa/inet.h> #include<signal.h> #include<wait.h>#define N 128 #define M 32#define ERRLOG(msg) do{\printf("%s %s(%d):", __FILE__, __func__, __LINE__);\perror(msg);\exit(-1);\ }while(0)typedef struct _Node{struct sockaddr_in addr; struct _Node *next; }node_t;typedef struct _Msg{char code;char user[M];char text[N]; }msg_t; #endif

服務器:server.c

#include "udp.h"//創建節點的函數 int create_node(node_t **phead){*phead = (node_t *)malloc(sizeof(node_t));if(NULL == *phead){printf("內存分配失敗\n");exit(-1);}(*phead)->next=NULL;return 0; } //尾插法 int insert_data_by_tail(node_t *phead,struct sockaddr_in addr){if(NULL == phead){printf("入參為NULL,請檢查\n");return -1;}//將新客戶端使用尾插法插入鏈表中node_t *pnew = NULL;create_node(&pnew);pnew->addr = addr; node_t *ptemp =phead;while(ptemp->next != NULL){ptemp = ptemp->next;}//讓尾結點的指針域指向新節點ptemp->next = pnew;return 0; }int main(int argc,const char *argv[]){ if(3 != argc){printf("Uage:%s <IP><port>\n",argv[0]);return -1;}int sockfd = 0;if(-1==(sockfd=socket(AF_INET,SOCK_DGRAM,0))){ERRLOG("socket error");}struct sockaddr_in serveraddr;memset(&serveraddr,0,sizeof(serveraddr));serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(atoi(argv[2]));serveraddr.sin_addr.s_addr = inet_addr(argv[1]);socklen_t serveraddr_len = sizeof(serveraddr);if(-1 == bind(sockfd,(struct sockaddr *)&serveraddr,serveraddr_len)){ERRLOG("bind error");} struct sockaddr_in clientaddr,temp_clientaddr;memset(&clientaddr,0,sizeof(clientaddr));socklen_t clientaddr_len = sizeof(clientaddr);char name[32] = {0};pid_t pid = 0;msg_t msg;msg_t msg_send;//創建頭結點node_t *phead;create_node(&phead);phead->addr = clientaddr;if(-1 == (pid = fork())){ERRLOG("fork error");}else if(0 == pid){ //子進程 接收數據 (1、d 登錄操作 2、q 群聊操作 3、t 退出操作) while(1){memset(&msg,0,sizeof(msg));if(-1 == recvfrom(sockfd, (void*)&msg, sizeof(msg),0, (struct sockaddr *)&clientaddr,&clientaddr_len)){perror("recv error");} switch(msg.code){// 1、d 登錄操作 2、q 群聊操作 3、t 退出操作 case 'd':printf("[%s]該玩家已上線\n", msg.user); insert_data_by_tail(phead,clientaddr);node_t *q=phead->next; while(q != NULL){msg.code='d';if(-1 == sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&q->addr,sizeof(q->addr))){ERRLOG("send error");}q=q->next;}break; case 'q': if(strcmp("管理員",msg.user)!=0){printf("[%s]:%s\n",msg.user, msg.text);}node_t *p = phead->next; while(p != NULL){msg.code='q';if(-1 == sendto(sockfd,(void *)&msg,sizeof(msg),0,(struct sockaddr *)&p->addr,sizeof(p->addr))){ERRLOG("send error");}p=p->next;} break; case 't': printf("[%s]:退出了...\n", msg.user);node_t *t = phead; node_t *pdel = NULL; while(t->next != NULL){msg.code='t';if( 0 == memcmp(&(t->next->addr), &clientaddr,sizeof(clientaddr))){pdel = t->next;t->next = pdel->next;free(pdel);}else{t = t->next;if(-1 == sendto(sockfd, &msg,sizeof(msg),0,(struct sockaddr *)&t->addr,sizeof(t->addr))){ERRLOG("send error");}} } break;}}}else if(0 < pid){//父進程 發送系統消息while(1){ strcpy(msg_send.user,"管理員");memset(msg_send.text,0,N);fgets(msg_send.text,N,stdin);msg_send.text[strlen(msg_send.text)-1] = '\0';msg_send.code = 'q'; if(-1 == sendto(sockfd,&msg_send,sizeof(msg_send),0,(struct sockaddr *)&serveraddr,serveraddr_len)){ERRLOG("send error"); } }} kill(pid, SIGKILL);wait(NULL);//給子進程回收資源exit(0); close(sockfd);return 0; }

?客戶端:client.c

#include "udp.h"int main(int argc, const char *argv[]) {if (3 != argc){printf("Usage: %s <IP> <port>\n", argv[0]);return -1;}//創建用戶數據報套接字int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (-1 == sockfd){ERRLOG("socket error");}//填充服務器網絡信息結構體struct sockaddr_in serveraddr;memset(&serveraddr, 0, sizeof(serveraddr));serveraddr.sin_family = AF_INET;//網絡字節序的端口號 8888 9999 6789 等 都可以serveraddr.sin_port = htons(atoi(argv[2]));//網絡字節序的IP地址,IP地址不能亂填//自己的主機ifconfig 查到的ip地址是多少就填多少//如果本機測試使用 也可以填寫 127.0.0.1serveraddr.sin_addr.s_addr = inet_addr(argv[1]);socklen_t serveraddr_len = sizeof(serveraddr);int nbytes = 0;char name[32]={0};msg_t msg;pid_t pid;struct sockaddr_in clientaddr;memset(&clientaddr,0,sizeof(clientaddr));socklen_t clientaddr_len = sizeof(clientaddr);//輸入用戶名,完成登陸操作printf("請輸入登錄信息:");msg.code = 'd';memset(msg.user, 0, M);fgets(name, M, stdin);//在終端獲取用戶名strcpy(msg.user,name);msg.user[strlen(msg.user) - 1] = '\0'; //清空結尾的 '\n' if (-1 == sendto(sockfd,&msg,sizeof(msg),0, (struct sockaddr *)&serveraddr,serveraddr_len)){ //給服務器發送用戶名ERRLOG("send error");}//創建進程if(-1 == (pid = fork())){ERRLOG("fork error");}else if(0 == pid){ //子進程 接收數據 while (1){memset(&msg,0,sizeof(msg));//接收服務器的應答if (-1 == (nbytes=recvfrom(sockfd, &msg, sizeof(msg), 0,(struct sockaddr *)&serveraddr,&serveraddr_len))){ERRLOG("recv error");} // printf("current ------->%d\n",strcmp(msg.user,name)); if(strcmp(msg.user,name) == -10){ continue;}else{//打印應答信息switch(msg.code){case 'd':printf("[%s]登錄上線了....\n", msg.user); break; case 'q':printf("[%s]:%s\n",msg.user,msg.text);break;case 't': printf("[%s]退出了....\n", msg.user); break;} } } }else if(0 < pid){//父進程 發送數據(2、q:群聊操作 3、t:退出操作)while(1){//在終端獲取群聊memset(msg.text, 0, N);fgets(msg.text, N, stdin);msg.text[strlen(msg.text) - 1] = '\0'; //清空結尾的 '\n' if( 0 ==strcmp(msg.text, "quit")){msg.code = 't'; if (-1 == sendto(sockfd, &msg, sizeof(msg), 0,(struct sockaddr *)&serveraddr,serveraddr_len)){ERRLOG("send error"); } break;}else{msg.code = 'q'; }//給服務器發送群聊消息if (-1 == sendto(sockfd, &msg, sizeof(msg), 0,(struct sockaddr *)&serveraddr,serveraddr_len)){ERRLOG("send error");}} } //關閉套接字close(sockfd);return 0; }

2.4 實現結果?

總結

以上是生活随笔為你收集整理的网络编程 : 基于UDP的网络群聊聊天室的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。