柚子快報(bào)激活碼778899分享:編程 udp聊天室
創(chuàng)建一個(gè)簡(jiǎn)單的udp聊天室
服務(wù)器代碼思路:
初始化:
創(chuàng)建UDP套接字。配置服務(wù)器的IP和端口號(hào),并綁定套接字到這個(gè)地址。 數(shù)據(jù)接收和處理:
使用循環(huán)接收客戶端發(fā)來(lái)的消息。recvfrom()解析消息類(lèi)型(如登錄、發(fā)送、下線)和內(nèi)容。 廣播消息:
對(duì)于聊天消息,將其廣播給所有連接的客戶端。對(duì)于登錄和下線消息,通知其他客戶端有新用戶上線或某用戶下線。 客戶端管理:
維護(hù)一個(gè)客戶端列表或字典,用于跟蹤在線客戶端的地址和狀態(tài)。更新客戶端列表以反映登錄和下線事件。 清理和關(guān)閉:
在服務(wù)器關(guān)閉時(shí),適當(dāng)清理資源并關(guān)閉套接字。
服務(wù)器代碼:
#include
typedef struct linklist { //創(chuàng)建存儲(chǔ)客戶端ip、端口號(hào)的鏈表 ? ? struct sockaddr_in addr; ? ? struct linklist *next; } l_node, *l_pnode;
typedef struct sockt_data { ? ? ? ? ? ? ? ? ? //創(chuàng)建收發(fā)的信息結(jié)構(gòu)體 ? ? char name[64]; ?//名字 ? ? char type[8]; ? //消息類(lèi)別 ? ? char text[128]; //信息內(nèi)容 } data_t;
typedef struct Sock { //創(chuàng)建存儲(chǔ)服務(wù)器發(fā)送數(shù)據(jù)的信息結(jié)構(gòu)體 ? ? struct sockaddr_in caddr; ? ? data_t cdata; //發(fā)送消息結(jié)構(gòu)體 ? ? int sockfd; ? //套接字 } sock_t;
l_pnode create(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//創(chuàng)建鏈表節(jié)點(diǎn) void login(int sockfd, data_t data, struct sockaddr_in saddr); //登錄 void line(int sockfd, data_t data, struct sockaddr_in saddr); ?//發(fā)送和下線 void *func(void *arg); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //子線程
l_pnode S; //開(kāi)辟一個(gè)全局變量的鏈表
int main(int argc, char *argv[]) { // ?1、創(chuàng)建套接字 -- socket? ? ? int sockfd = socket(AF_INET, SOCK_DGRAM, 0); ? ? // 2、綁定IP地址和端口號(hào) -- bind ? ? struct sockaddr_in saddr, caddr;
? ? caddr.sin_family = AF_INET; ? ? caddr.sin_port = htons(8888); //將主機(jī)字節(jié)序轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)序再賦值 ? ? caddr.sin_addr.s_addr = htons(INADDR_ANY);
? ? int s_len = sizeof(saddr); ? ? bind(sockfd, (struct sockaddr *)&caddr, s_len); ? ? // 3、發(fā)送接送數(shù)據(jù)? ? ? data_t sdata = {0, 0, 0}; //定義接送數(shù)據(jù)結(jié)構(gòu)體 ? ? int d_len = sizeof(sdata); ? ? int c_len = sizeof(caddr); //計(jì)算服務(wù)器地址結(jié)構(gòu)的大小 ? ? memset(&saddr, 0, c_len); ?//清空接收地址結(jié)構(gòu)
? ? S = (l_pnode)malloc(sizeof(l_node)); //初始化鏈表 ? ? S->next = NULL;
? ? sock_t csock; ? ? ? ? ?//創(chuàng)建子線程所需結(jié)構(gòu)體 ? ? csock.sockfd = sockfd; //傳遞套接字
? ? pthread_t thread; ? ? pthread_create(&thread, NULL, func, &csock); //創(chuàng)建子線程
? ? while (1) ? ? { ? ? ? ? memset(&sdata, 0, d_len); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//清空接送到的數(shù)據(jù) ? ? ? ? recvfrom(sockfd, &sdata, d_len, 0, (struct sockaddr *)&saddr, &c_len); //接送來(lái)自客戶端的消息 ? ? ? ? printf("%s:%s\n", sdata.name, sdata.text); ? ? ? ? ? ? ? ? ? ? ? ? ? ? //在服務(wù)器中顯示接送到的消息 ? ? ? ? if (strcmp(sdata.type, "login") == 0) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//判斷接受消息內(nèi)型 ? ? ? ? ? ? login(sockfd, sdata, saddr); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //上線操作 ? ? ? ? else ? ? ? ? ? ? line(sockfd, sdata, saddr); //聊天、下線操作 ? ? } // ? 4、關(guān)閉套接字? ? ? close(sockfd); ? ? return 0; } // ?子線程? void *func(void *arg) //線程處理函數(shù) { ? ? sock_t csock = *(sock_t *)arg; ? ? //獲取主函數(shù)中傳遞過(guò)來(lái)的內(nèi)容 ? ? strcpy(csock.cdata.type, "login"); //設(shè)置要發(fā)送的結(jié)構(gòu)圖 ? ? strcpy(csock.cdata.name, "服務(wù)器"); ? ? while (1) ? ? { ? ? ? ? memset(&csock.cdata.text, 0, 128); ? ? ? ? ? ? ? ? ? ? //清空輸入進(jìn)來(lái)的內(nèi)容 ? ? ? ? fgets(csock.cdata.text, 64, stdin); ? ? ? ? ? ? ? ? ? ?//獲取輸入進(jìn)來(lái)的內(nèi)容 ? ? ? ? csock.cdata.text[strlen(csock.cdata.text) - 1] = '\0'; //刪除獲取進(jìn)來(lái)的回車(chē)'\n' ? ? ? ? line(csock.sockfd, csock.cdata, csock.caddr); ? ? ? ? ?//向所有在線的客戶端發(fā)送入進(jìn)來(lái)的內(nèi)容 ? ? } } // ?上線? void login(int sockfd, data_t data, struct sockaddr_in saddr) //登錄 { ? ? int d_len = sizeof(data); ? ? int s_len = sizeof(saddr); ? ? l_pnode new = create(); //創(chuàng)建新節(jié)點(diǎn) ? ? new->addr = saddr; ? ? ?//傳遞接送到的客戶端IP、端口號(hào) ? ? new->next = NULL; ? ? l_pnode N = create(); ? ? N = S; ? ? while (N->next) //尾插并發(fā)送給其他客戶端 ? ? { ? ? ? ? N = N->next; ? ? ? ? sendto(sockfd, &data, d_len, 0, (struct sockaddr *)&N->addr, s_len); //發(fā)送給除該客戶信息的其他客戶 ? ? } ? ? N->next = new; } // ?聊天、下線? void line(int sockfd, data_t data, struct sockaddr_in saddr) //聊天、下線 { ? ? int d_len = sizeof(data); ? ? int s_len = sizeof(saddr); ? ? l_pnode N = create(); ? ? N = S; ? ? while (N->next) ? ? { ? ? ? ? if ((N->next->addr.sin_addr.s_addr == saddr.sin_addr.s_addr) && (N->next->addr.sin_port == saddr.sin_port)) //判斷是否存在該客戶端數(shù)據(jù) ? ? ? ? { ? ? ? ? ? ? if (strcmp(data.type, "line") == 0) //下線,刪除用戶信息 ? ? ? ? ? ? { ? ? ? ? ? ? ? ? l_pnode Q = N->next; ? ? ? ? ? ? ? ? N->next = Q->next; //連線 ? ? ? ? ? ? ? ? free(Q); ? ? ? ? ? //釋放空間 ? ? ? ? ? ? ? ? Q = NULL; ? ? ? ? ? ? } ? ? ? ? ? ? if (strcmp(data.type, "send_t") == 0) //聊天,跳過(guò)用戶 ? ? ? ? ? ? ? ? N = N->next; ? ? ? ? } ? ? ? ? if (N->next != NULL) //判斷是否到尾節(jié)點(diǎn) ? ? ? ? { ? ? ? ? ? ? N = N->next; ? ? ? ? ? ? sendto(sockfd, &data, d_len, 0, (struct sockaddr *)&N->addr, s_len); //發(fā)送給除該客戶信息的其他客戶 ? ? ? ? } ? ? ? ? else ? ? ? ? ? ? break; ? ? } } // ?創(chuàng)建鏈表新節(jié)點(diǎn) l_pnode create() { ? ? l_pnode S = (l_pnode)malloc(sizeof(l_node)); ? ? S->next = NULL; ? ? return S; }
客戶端代碼思路:
初始化和創(chuàng)建套接字:在函數(shù)中,創(chuàng)建一個(gè)UDP套接字,并配置客戶端的IP地址和端口。main 進(jìn)程創(chuàng)建:使用創(chuàng)建一個(gè)子進(jìn)程。子進(jìn)程負(fù)責(zé)讀取用戶輸入的用戶名和消息,并處理登錄、發(fā)送和下線操作。fork() 父進(jìn)程接收消息:父進(jìn)程不斷接收來(lái)自服務(wù)器的消息,并在控制臺(tái)顯示。 登錄、發(fā)送和下線功能:
login():向服務(wù)器發(fā)送登錄消息。send_t():發(fā)送聊天消息。line():發(fā)送下線消息并退出子進(jìn)程。 信號(hào)處理:使用處理子進(jìn)程結(jié)束的信號(hào),確保子進(jìn)程資源得到清理。signal(SIGCHLD, mysignal)
客戶端代碼:
#include
void mysignal(int arg) //回收子進(jìn)程 { ? ? wait(NULL); ? ? exit(0); }
void login(int sockfd, data_t cdata, struct sockaddr_in caddr); //登錄 void send_t(int sockfd, data_t data, struct sockaddr_in saddr); //發(fā)送信息 void line(int sockfd, data_t cdata, struct sockaddr_in caddr); ?//下線
int main(int argc, char *argv[]) { ? ? if (argc != 2) ? ? ? ? printf("請(qǐng)正確輸入: ./client IP號(hào)\n"); ? ? // ?1、創(chuàng)建套接字 ? ? int sockfd = socket(AF_INET, SOCK_DGRAM, 0); ? ? // 2、綁定IP地址和端口號(hào) -- bind ? ? struct sockaddr_in saddr, caddr; ? ? caddr.sin_family = AF_INET; ? ? caddr.sin_port = htons(8888); //將主機(jī)字節(jié)序轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)序再賦值 ? ? caddr.sin_addr.s_addr = inet_addr(argv[1]);
? ? int s_len = sizeof(saddr); ? ? // ?3、發(fā)送接送數(shù)據(jù) ? ? data_t cdata = {0, 0, 0}, sdata = {0, 0, 0}; //定義收發(fā)數(shù)據(jù)結(jié)構(gòu)體
? ? int d_len = sizeof(cdata); //計(jì)算數(shù)據(jù)結(jié)構(gòu)體長(zhǎng)度
? ? memset(&saddr, 0, s_len); ?//清空接收地址結(jié)構(gòu) ? ? memset(&cdata, 0, d_len); ?//清空接收地址結(jié)構(gòu) ? ? signal(SIGCHLD, mysignal); //捕獲子進(jìn)程釋放信號(hào)
? ? pid_t pid = fork(); //創(chuàng)建線程 ? ? if (0 == pid) ? ? ? //子線程 ? ? { ? ? ? ? printf("請(qǐng)輸入你的用戶名--->"); ? ? ? ? fgets(cdata.name, 64, stdin); ? ? ? ? ? ? ?//獲取輸入進(jìn)來(lái)的名字 ? ? ? ? cdata.name[strlen(cdata.name) - 1] = '\0'; //刪除獲取進(jìn)來(lái)的回車(chē)'\n' ? ? ? ? login(sockfd, cdata, caddr); ? ? ? ? ? ? ? //登錄
? ? ? ? while (1) ? ? ? ? { ? ? ? ? ? ? fgets(cdata.text, 64, stdin); ? ? ? ? ? ? ?//獲取輸入進(jìn)來(lái)的內(nèi)容 ? ? ? ? ? ? cdata.text[strlen(cdata.text) - 1] = '\0'; //刪除獲取進(jìn)來(lái)的回車(chē)'\n' ? ? ? ? ? ? if (strcmp(cdata.text, "line!!!") == 0) ? ?//判斷是否結(jié)束聊天 ? ? ? ? ? ? ? ? line(sockfd, cdata, caddr); ? ? ? ? ? ?//下線 ? ? ? ? ? ? send_t(sockfd, cdata, caddr); ? ? ? ? ? ? ?//聊天 ? ? ? ? } ? ? }
? ? while (1) ? ? { ? ? ? ? memset(&sdata, 0, d_len); //清空接送到的數(shù)據(jù) ? ? ? ? recvfrom(sockfd, &sdata, d_len, 0, (struct sockaddr *)&saddr, &s_len); ? ? ? ? if (strcmp(sdata.type, "send_t") == 0) //在客戶端中顯示接送到的消息 ? ? ? ? ? ? printf("%s:%s\n", sdata.name, sdata.text); ? ? ? ? else ? ? ? ? ? ? printf("%s-->%s\n", sdata.name, sdata.text); ? ? } ? ? // ?4、關(guān)閉套接字 ? ? close(sockfd); ? ? return 0; } // 登錄 void login(int sockfd, data_t cdata, struct sockaddr_in caddr) //登錄 { ? ? int d_len = sizeof(cdata); ? ? int s_len = sizeof(caddr); ? ? strcpy(cdata.type, "login"); ? ? strcpy(cdata.text, "上線了"); ? ? sendto(sockfd, &cdata, d_len, 0, (struct sockaddr *)&caddr, s_len); } // ? ?下線 void line(int sockfd, data_t cdata, struct sockaddr_in caddr) //下線 { ? ? int d_len = sizeof(cdata); ? ? int s_len = sizeof(caddr); ? ? strcpy(cdata.type, "line"); ? ? strcpy(cdata.text, "下線了"); ? ? sendto(sockfd, &cdata, d_len, 0, (struct sockaddr *)&caddr, s_len); ? ? exit(0); } // 聊天 void send_t(int sockfd, data_t cdata, struct sockaddr_in caddr) //發(fā)送信息 { ? ? int ret = 0; ? ? int d_len = sizeof(cdata); ? ? int s_len = sizeof(caddr); ? ? strcpy(cdata.type, "send_t"); ? ? ret = sendto(sockfd, &cdata, d_len, 0, (struct sockaddr *)&caddr, s_len); }
柚子快報(bào)激活碼778899分享:編程 udp聊天室
精彩鏈接
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。
轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。