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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

c语言 多进程实现基于UDP的网络群聊聊天室

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

功能

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

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

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

服務器可以發送系統信息

流程圖如下:

?

提示:

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

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

服務器需要給多個用戶發送數據,所以需要保存每一個用戶的信息,使用鏈表來保存數據傳輸的時候要定義結構體,結構體中包含操作碼、用戶名以及數據。

代碼如下:

? ? ? ? 服務器代碼

//服務器代碼 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/ip.h> #include <arpa/inet.h>#define ERRLOG(msg) \do { \printf("%s %s %d:", __FILE__, __func__, __LINE__); \perror(msg); \exit(-1); \} while (0)typedef struct _MSG {char code; //操作碼 ('L' 登錄),('C' 群聊),('Q' 退出)char name[32];char txt[128]; } msg_t; typedef struct _NODE {struct sockaddr_in clientaddr; //客戶端網絡信息結構體struct _NODE* next; //指針域 } node_t;int create_node(node_t **p); int do_login(struct sockaddr_in clientaddr, node_t* phead, int sockfd, msg_t msg); int do_chat(struct sockaddr_in clientaddr, node_t* phead, int sockfd, msg_t msg); int do_quit(struct sockaddr_in clientaddr, node_t* phead, int sockfd, msg_t msg); int main(int argc, char const* argv[]) {//入參合理性檢查if (3 != argc) {printf("Usage : %s <IP> <PORT>\n", argv[0]);return -1;}// 1.創建套接字int sockfd = 0;if (-1 == (sockfd = socket(AF_INET, SOCK_DGRAM, 0))) {ERRLOG("socket error");}// 2.填充服務器網絡信息結構體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;socklen_t clientaddr_len = sizeof(clientaddr);msg_t msg;pid_t pid = 0;if (-1 == (pid = fork())) {ERRLOG("fork error");} else if (0 == pid) {//子進程,用來接收數據并處理//創建用來保存客戶端網絡信息結構體的鏈表node_t *phead = NULL;create_node(&phead);phead->next =NULL;printf("聊天室已創建,等待用戶加入群聊!!!\n");while(1) {memset(&msg, 0, sizeof(msg));memset(&clientaddr, 0, sizeof(clientaddr));if (-1 == recvfrom(sockfd, &msg, sizeof(msg), 0, (struct sockaddr*)&clientaddr, &clientaddr_len)) {ERRLOG("recvfrom error");}printf("[%s]: [%s]\n", msg.name, msg.txt);switch (msg.code) {case 'L':do_login(clientaddr, phead, sockfd,msg);break;case 'C':do_chat(clientaddr, phead, sockfd, msg);break;case 'Q':do_quit(clientaddr, phead, sockfd, msg);break;}}} else if (0 < pid) {//父進程,用來發送系統消息//把父進程當作一個客戶端,以群聊的方式發送消息給所有人(系統消息)msg.code = 'C';strcpy(msg.name, "系統");while (1){fgets(msg.txt, 128, stdin);msg.txt[strlen(msg.txt) - 1] = '\0';if (-1 == sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr*)&serveraddr, serveraddr_len)) {ERRLOG("sendto error");}}}close(sockfd);return 0; } //創建鏈表節點的函數 int create_node(node_t** p) {*p = (node_t*)malloc(sizeof(node_t));if (NULL == *p || NULL == p) {ERRLOG("malloc error");} } //登錄的函數 int do_login(struct sockaddr_in clientaddr, node_t* phead, int sockfd, msg_t msg) {//先遍歷鏈表,將xxxx登錄的消息 轉發給所有人node_t* ptemp = phead;while (ptemp->next != NULL) {ptemp = ptemp->next;if (-1 == sendto(sockfd, &msg, sizeof(msg), 0, ((struct sockaddr*)&(ptemp->clientaddr)), sizeof(ptemp->clientaddr))) {ERRLOG("sendto error");}}//將新登錄的用戶頭插到鏈表中node_t* pnew = NULL;create_node(&pnew);pnew->clientaddr = clientaddr;pnew->next = phead->next;phead->next = pnew;return 0; }//群聊消息的函數 int do_chat(struct sockaddr_in clientaddr, node_t* phead, int sockfd, msg_t msg) {//遍歷鏈表,將群聊的數據發送給除自己外的所有人node_t* ptemp = phead;while (ptemp->next != NULL) {ptemp = ptemp->next;if (0 != memcmp(&clientaddr, &(ptemp->clientaddr), sizeof(clientaddr))) {if (-1 == sendto(sockfd, &msg, sizeof(msg), 0, ((struct sockaddr*)&(ptemp->clientaddr)), sizeof(ptemp->clientaddr))) {ERRLOG("sendto error");}}} }int do_quit(struct sockaddr_in clientaddr, node_t* phead, int sockfd, msg_t msg) {//將xxxx退出群聊的消息發送給除自己外所有的所有客戶端,并且將自己在鏈表中刪除node_t* ptemp = phead;while (ptemp->next != NULL) {if (0 != memcmp(&clientaddr, &(ptemp->clientaddr), sizeof(clientaddr))) {//判斷是不是自己,不是自己就發送數據ptemp = ptemp->next;if (-1 == sendto(sockfd, &msg, sizeof(msg), 0, ((struct sockaddr*)&(ptemp->clientaddr)), sizeof(ptemp->clientaddr))) {ERRLOG("sendto error");}} else {//是自己,就將自己在鏈表中刪除node_t* pdel = ptemp->next;ptemp->next = pdel->next;free(pdel);pdel == NULL;}} }

? ? ? ? 客戶端代碼

//客戶端代碼 #include <arpa/inet.h> #include <netinet/in.h> #include <netinet/ip.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #define ERRLOG(msg) \do { \printf("%s %s %d:", __FILE__, __func__, __LINE__); \perror(msg); \exit(-1); \} while (0)typedef struct _MSG {char code; //操作碼 ('L' 登錄),('C' 群聊),('Q' 退出)char name[32];char txt[128]; } msg_t; int main(int argc, const char* argv[]) {//入參合理性檢查if (3 != argc) {printf("Usage : %s <IP> <PORT>\n", argv[0]);return -1;}// 1.創建套接字int sockfd = 0;if (-1 == (sockfd = socket(AF_INET, SOCK_DGRAM, 0))) {ERRLOG("socket error");}// 2.填充服務器網絡信息結構體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);msg_t msg;memset(&msg, 0, sizeof(msg));printf("請輸入用戶名: ");fgets(msg.name, 32, stdin);msg.name[strlen(msg.name) - 1] = '\0';//給服務器發送登錄的數據包msg.code = 'L';strcpy(msg.txt, "加入群聊");if (-1 == sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr*)&serveraddr, serveraddr_len)) {ERRLOG("sendto error");}pid_t pid = 0;if (-1 == (pid = fork())) {ERRLOG("fork error");} else if (0 == pid) {//子進程//接收由服務器發來的數據并打印while (1) {memset(&msg, 0, sizeof(msg));if (-1 == recvfrom(sockfd, &msg, sizeof(msg), 0, NULL, NULL)) {ERRLOG("recvfrom error");}printf("[%s]: [%s]\n", msg.name, msg.txt);}} else if (0 < pid) {//父進程while (1) {msg.code = 'C';fgets(msg.txt, 128, stdin);printf("我: ");msg.txt[strlen(msg.txt) - 1] = '\0';//判斷是不是要退出if (!strncmp(msg.txt, "quit", 5)) {msg.code = 'Q';strcpy(msg.txt, "退出群聊");}if (-1 == sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr*)&serveraddr, serveraddr_len)) {ERRLOG("sendto error");}if (!strcmp(msg.txt, "退出群聊")) {break;}}//先讓子進程自殺kill(pid, SIGKILL);wait(NULL);close(sockfd);}return 0; }

總結

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

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

主站蜘蛛池模板: 欧美大浪妇猛交饥渴大叫 | 黄色网免费看 | 国产精品电影在线观看 | 蜜臀视频在线播放 | 911国产在线| 日韩精品一区二区三区免费视频 | 国产三级视频在线 | 91成人在线观看国产 | 国产成人久久精品77777综合 | 制服丝袜av一区二区三区下载 | 国产福利精品在线 | 传媒一区二区 | 免费毛片网站在线观看 | 成人人伦一区二区三区 | 另类小说一区二区 | 欧美一级爱爱视频 | 日韩乱码人妻无码中文字幕 | 亚洲男性天堂 | 久久在线 | 成人网一区 | 免费黄毛片 | 草草网址 | 成人精品一区二区三区电影 | 国产精品aaa | 国产情侣91 | 成人激情视频在线播放 | 成人久久网站 | 欧美日韩亚洲不卡 | 吃奶在线观看 | 色噜噜在线观看 | www.爱爱.com| 亚洲精品日韩在线观看 | 超碰av男人的天堂 | 午夜小视频在线播放 | 蜜桃视频在线观看一区 | 欧美tickle狂笑裸体vk | 她也啪在线视频 | 精品人妻一区二区色欲产成人 | 杨幂国产精品一区二区 | 午夜伦理一区二区 | 日日夜夜av | www.88av| 午夜视频福利在线 | 黄色网战入口 | 欧美视频区 | 国产精品一级 | 亚洲永久精品一区 | 黄色a免费 | 女女互磨互喷水高潮les呻吟 | 青青草操 | 一区二区不卡免费视频 | 男人天堂久久 | 在线看国产 | 内射国产内射夫妻免费频道 | 久久免费精品视频 | 国产欧美另类 | 韩国伦理片在线看 | 自拍偷拍亚洲精品 | 久久亚洲无码视频 | 最近免费中文字幕大全免费版视频 | 男生和女生差差的视频 | www久久| 999精品在线视频 | 一级黄色在线观看 | 在线播放黄色av | 99亚洲视频 | 成人乱码一区二区三区 | 欧美日韩国产区 | 日本少妇videos高潮 | 91视频久久 | 四虎国产精品永久免费观看视频 | 奇米网久久 | 午夜黄色在线观看 | 成年人91视频 | 天天色宗合 | 国产高清视频在线免费观看 | 色姑娘综合网 | 污网站在线看 | 亚洲乱色 | 青娱乐国产视频 | 黄色资源在线观看 | 国产精品电影一区二区 | 波多野结衣在线电影 | 美女日日日 | 国产原创在线播放 | 国语粗话呻吟对白对白 | 91精品视频网站 | 午夜国产片 | 无码精品一区二区三区在线播放 | 色婷婷久久 | 成色网| 亚洲精品国产suv | 欧美性日韩 | 亚洲av无码国产精品久久不卡 | 免费一区二区 | 91羞羞网站 | 国产欧美第一页 | 久久黄色 | 国自产拍偷拍精品啪啪一区二区 |