基于UDP的網絡多人聊天室

UDP服務器

#include <myheader.h>//宏定義打印錯誤信息
#define PRINT_ERR(msg)                                  \do                                                  \{                                                   \printf("%S,%D,%S\n",__FILE__,__LINE__,__func__);\perror(msg);                                    \exit(-1);                                       \}while(0);//定義一個結構體
//由于客戶端給服務器發送第數據內容較多,定義一個結構體來發送
typedef struct
{char code;  //操作碼 ‘L’登錄 ‘C’群聊 ‘Q’退出char name[32];   //保存登錄用戶名char txt[128];   //保存發送的信息
}msg_t;//定義一個鏈表
// 給在線所有客戶端發送數據,將每一個客戶端的信息用鏈表來保存
typedef struct NODE
{struct sockaddr_in c_addr;   //數據域  客戶端第網絡信息結構體struct NODE *next;   // 指針域   保存下一個結點的地址
}node_t;//創建一個鏈表頭第函數,定義鏈表頭結點
//鏈表頭結點函數
void creat_link(node_t **head)
{*head = (node_t *)malloc(sizeof(node_t));
}int do_register(int sockfd, msg_t msg, struct sockaddr_in clientaddr, node_t *phead)
{//遍歷鏈表將登錄信息發送給所以人node_t *p = phead;while (p->next != NULL){p = p->next;if (sendto(sockfd, &msg, sizeof(msg_t), 0, (struct sockaddr *)&(p->c_addr), sizeof(p->c_addr)) == -1){perror("recvfrom error");}}//將登錄的客戶端信息插入保存在鏈表//頭插//定義一個新的指針保存客戶端信息node_t *newp = NULL;creat_link(&newp);newp->c_addr = clientaddr;newp->next = phead->next;phead->next = newp;return 0;
}int do_group_chat(int sockfd, msg_t msg, struct sockaddr_in clientaddr, node_t *phead)
{//遍歷鏈表,將消息發給除自己之外的所有人node_t *p = phead;while (p->next != NULL){p = p->next;//判斷鏈表客戶端信息是否是自己//是自己就不發送if (memcmp(&(p->c_addr), &clientaddr, sizeof(clientaddr))){if (sendto(sockfd, &msg, sizeof(msg_t), 0, (struct sockaddr *)&(p->c_addr), sizeof(p->c_addr)) == -1){perror("recvfrom error");}}}return 0;
}//退出群聊操作
int quit_group_chat(int sockfd, msg_t msg, struct sockaddr_in clientaddr, node_t *phead)
{node_t *p = phead;while (p->next != NULL){//判斷鏈表客戶端信息是否是自己//是自己就不發送并且將自己的客戶端信息在鏈表內刪除if (memcmp(&(p->next->c_addr), &clientaddr, sizeof(clientaddr))){p = p->next;if (sendto(sockfd, &msg, sizeof(msg_t), 0, (struct sockaddr *)&(p->c_addr), sizeof(p->c_addr)) == -1){perror("recvfrom error");}}else{node_t *pnew;pnew = p->next;p->next = pnew->next;pnew->next = NULL;free(pnew);pnew = NULL;}}return 0;
}int main(int argc, const char *argv[])
{//入參合理性判斷if(argc != 3){printf("age:%s ip port\n",argv[0]);return -1;}//創建套接字int sfd = socket(AF_INET,SOCK_DGRAM,0);if(sfd == -1){perror("socket error");return -1;}printf("sfd = %d\n",sfd);//創建服務器網絡信息結構體struct sockaddr_in sin;memset(&sin,0,sizeof(sin));sin.sin_family = AF_INET;sin.sin_port = htons(atoi(argv[2]));sin.sin_addr.s_addr = inet_addr(argv[1]);socklen_t sin_len = sizeof(sin);//綁定if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin)) == -1){perror("bind error");return -1;}printf("bind success\n");//創建客戶端的網絡信息結構體struct sockaddr_in cin;memset(&cin,0,sizeof(cin));socklen_t cin_len = sizeof(cin);msg_t msg;//建一個父子進程 //用來實現服務器既可以發送系統消息,又可以接收客戶端的信息pid_t pid;pid = fork();if(pid == -1){//創建錯誤perror("fork error");}else if(pid == 0){//子進程//接收數據并處理//循環接收客戶端發來的信息,通過Switch判斷code所存的協議//定義鏈表頭結點node_t *phead = NULL;creat_link(&phead);phead->next = NULL;//循環接受客戶端發來的信息并通過switch進行判斷執行哪個功能函數while (1){memset(&msg, 0, sizeof(msg));//清空操作memset(&cin, 0, sizeof(cin));//清空操作if ((recvfrom(sfd, &msg, sizeof(msg), 0, (struct sockaddr *)&cin, &cin_len)) == -1){perror("recvfrom error");}printf("%8s : [%s]\n", msg.name, msg.txt);switch (msg.code){case 'L':do_register(sfd, msg, cin, phead);break;case 'C':do_group_chat(sfd, msg, cin, phead);break;case 'Q':quit_group_chat(sfd, msg, cin, phead);break;}}}else if(pid > 0){//父進程//發送系統信息//視為一個客戶端,向子進程發送消息給在線客戶msg.code='C';strcpy(msg.name,"server");while(1){fgets(msg.txt,128,stdin);msg.txt[strlen(msg.txt)-1]='\0';if(sendto(sfd,&msg,sizeof(msg_t),0,(struct sockaddr *)&sin,sin_len)==-1){perror("sendto error");}}close(sfd);return 0;}return 0;
}

UDP客戶端

#include <myheader.h>//宏定義打印錯誤信息
#define perror(msg)                                      \do                                                      \{                                                       \printf("%s,%d,%s\n", __FILE__, __LINE__, __func__); \perror(msg);                                        \exit(-1);                                           \} while (0)typedef struct
{char code; //操作碼 'L' 登錄  'C' 群聊  'Q' 退出char name[32];char txt[128];
} msg_t;int main(int argc, const char *argv[])
{//入參合理性判斷if (argc != 3){printf("age:%s ip port\n", argv[0]);return -1;}//創建套接字int sfd;if ((sfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1){perror("socket error");}//創建服務器網絡信息結構體struct sockaddr_in sin;memset(&sin, 0, sizeof(sin));sin.sin_family = AF_INET;sin.sin_addr.s_addr = inet_addr(argv[1]);sin.sin_port = htons(atoi(argv[2]));socklen_t sin_len = sizeof(sin);//給服務器發送登錄數據包msg_t msg;memset(&msg, 0, sizeof(msg_t));msg.code = 'L';printf("請輸入用戶名:");fgets(msg.name, 32, stdin);msg.name[strlen(msg.name) - 1] = '\0';strcpy(msg.txt, "加入群聊");if (sendto(sfd, &msg, sizeof(msg_t), 0, (struct sockaddr *)&sin, sin_len) == -1){perror("sendto error");}//創建父子進程pid_t pid;pid = fork();if (pid == -1){perror("fork error");}else if (pid == 0){//子進程//接受數據并處理while (1){//每次循環前將msg置零memset(&msg, 0, sizeof(msg));//接受服務器發過來的信息并打印到終端上if (recvfrom(sfd, &msg, sizeof(msg_t), 0, NULL, NULL) == -1){perror("recvfrom error");}printf("%8s:[%s]\n", msg.name, msg.txt);}}else if (pid > 0){//父進程//發送消息while (1){   //memset會把name清除msg.code = 'C';fgets(msg.txt, 128, stdin);msg.txt[strlen(msg.txt) - 1] = '\0';if (strcmp(msg.txt, "quit") == 0){msg.code = 'Q';strcpy(msg.txt, "退出群聊");}if (sendto(sfd, &msg, sizeof(msg_t), 0, (struct sockaddr *)&sin, sin_len) == -1){perror("sendto error");}if (strcmp(msg.txt, "退出群聊") == 0){break;}}kill(pid,SIGKILL);wait(NULL);close(sfd);}return 0;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/15494.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/15494.shtml
英文地址,請注明出處:http://en.pswp.cn/web/15494.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

java單元測試:編寫可測試性好的代碼

寫出可測試性好的代碼是編寫高質量軟件的關鍵。以下是一些有助于提高代碼可測試性的最佳實踐&#xff1a; 1. 單一職責原則 (Single Responsibility Principle) 每個類或方法應只負責一個功能。這樣可以讓測試更容易集中于單一功能。 2. 依賴注入 (Dependency Injection) 通…

【一個糟糕的詞:省流】

今日思考&#xff0c;博主分享&#x1f4dd;&#xff0c;原文如下&#xff0c; 我最近聽到了一個特別糟糕的詞叫省流。我甚至認為這個詞可以用來衡量一個人的智商啊&#xff0c;我們可以把一個知識簡單的分成三部分問題&#xff0c;答案思維方式就是這個答案是怎么推導出來的啊…

Python數據可視化(二)

Patches繪制幾何圖形 模塊 patches 主要用來完成多邊形的繪制工作。這些多邊形都是以類&#xff08;Class&#xff09;的形式出現的&#xff0c; 主要包括圓&#xff08;Circle&#xff09;、橢圓&#xff08;Ellipse&#xff09;、矩形&#xff08;Rectangle&#xff09;、圓…

SFTP命令用法(上傳和下載 )

sftp&#xff08;Secure File Transfer Protocol&#xff09;是SSH協議的一部分&#xff0c;用于在加密的SSH傳輸上訪問、管理和傳輸文件。與傳統的FTP協議相比&#xff0c;sftp提供了FTP的所有功能&#xff0c;但它更安全&#xff0c;更容易配置。不像SCP&#xff0c;它只支持…

【全開源】知識庫文檔系統源碼(ThinkPHP+FastAdmin)

知識庫文檔系統源碼&#xff1a;構建智慧知識庫的基石 引言 在當今信息爆炸的時代&#xff0c;知識的有效管理和利用對于企業和個人來說至關重要。知識庫文檔系統源碼正是為了滿足這一需求而誕生的&#xff0c;它提供了一個高效、便捷的平臺&#xff0c;幫助用戶構建、管理、…

設計模式之創建型模式---原型模式(ProtoType)

文章目錄 概述類圖原型模式優缺點優點缺點 代碼實現 概述 在有些系統中&#xff0c;往往會存在大量相同或者是相似的對象&#xff0c;比如一個圍棋或者象棋程序中的旗子&#xff0c;這些旗子外形都差不多&#xff0c;只是演示或者是上面刻的內容不一樣&#xff0c;若此時使用傳…

Oblivion Desktop:一款強大的網絡工具介紹

一款優秀的開源網絡工具。 文章目錄 Oblivion Desktop: 安全與隱私的網絡工具軟件背景開發背景 使用方法安裝日常使用高級功能 總結 Oblivion Desktop: 安全與隱私的網絡工具 軟件背景 Oblivion Desktop 是一個由 BePass 團隊開發的開源桌面應用&#xff0c;旨在為用戶提供更…

【Qt】Qt組件設置背景圖片

1. 方法1&#xff08;paintEvent方式&#xff09; 使用paintEvent()實現 1. .h文件中添加虛函數 protected:void paintEvent(QPaintEvent *event) override;添加虛函數方法&#xff1a; 選中父類&#xff0c;點擊鼠標右鍵點擊重構點擊 Insert Virtual Funtion of Base Class…

NebulaGraph

文章目錄 關于 NebulaGraph客戶端支持安裝 NebulaGraph關于 nGQLnGQL 可以做什么2500 條 nGQL 示例原生 nGQL 和 openCypher 的關系 Backup&Restore功能 導入導出導入工具導出工具 NebulaGraph ImporterNebulaGraph ExchangeNebulaGraph Spark ConnectorNebulaGraph Flink …

python中的可哈希和不可哈希

python 中的每一個對象都有一個哈希值&#xff0c;哈希值是一個固定長度的整數&#xff0c;它通常用于快速比較對象的相等性。 如果在對象的生命周期里該對象的哈希值從未改變&#xff0c;那么這個對象是可哈希的&#xff08;hashable&#xff09;&#xff0c;也稱為不可變的。…

第一篇【傳奇開心果系列】Python的跨平臺開發工具beeware技術點案例示例:使用beeware實現跨平臺開發,從hello world開始

傳奇開心果博文系列 系列博文目錄Python的跨平臺開發工具beeware技術點案例示例系列 博文目錄前言一、BeeWare套件主要功能介紹二、Toga相對于其他Python UI庫具有的優勢介紹三、使用toga開發安卓手機應用hello world步驟和示例代碼四、使用toga寫一個iOS 蘋果手機應用hello wo…

【文末附gpt升級方案】亞馬遜與Hugging Face合作:定制芯片低成本運行AI模型的創新探索

亞馬遜與Hugging Face合作&#xff1a;定制芯片低成本運行AI模型的創新探索 摘要 本文探討了亞馬遜云部門與人工智能初創公司Hugging Face的合作&#xff0c;旨在通過定制計算芯片Inferentia2在亞馬遜網絡服務&#xff08;AWS&#xff09;上更低成本地運行數千個AI模型。文章首…

web前端之vue的生命周期、unmounted、onUnmounted、activated、deactivated、keep-alive

MENU 前言vue2vue3activated和deactivated 前言 在Vue.js中&#xff0c;組件生命周期鉤子函數定義了在組件的不同階段執行的操作。Vue 2.x和Vue 3.x之間的生命周期鉤子函數有一些區別。 vue2 1、beforeCreate: 在實例初始化之后&#xff0c;數據觀測(data observer)和event/wat…

RDD介紹

RDD設計背景 在實際應用中,存在許多迭代式計算,這些應用場景的共同之處是 : 不同計算階段之間會重用中間結果,即一個階段的輸出結果會作為下一個階段的輸入. 而目前的MapReduce框架都是把中間結果寫入到HDFS中,帶來了大量的數據復制、磁盤IO和序列化開銷; 如果能將結果保存在內…

為何程序員35歲就開始被嫌棄了?程序員該如何避免中年危機?

文章目錄 一、為何程序員35歲就開始被嫌棄了&#xff1f;1、技術更新迅速2、職業發展瓶頸3、成本考慮4、年齡歧視5、市場供需變化6、個人因素 二、程序員該如何避免中年危機&#xff1f;1、持續學習與技能更新2、拓展技術廣度與深度3、提升軟技能4、關注行業趨勢與市場變化5、建…

vue3 input輸入框輸入限制(數字)

輸入框限制輸入的內容格式&#xff0c;如&#xff08;金額&#xff0c;數字&#xff09; 金額限制小數點后2位數 <el-input placeholder"請填寫費用" v-model"formMoney.total_money" keyup"formMoney.total_money checkPrice(formMoney.total_…

20240521(代碼整潔和測試入門學習)

測試: 1.測試工程師、測試工具開發工程師、自動化測試工程師。 python&#xff1a; 1、發展背景和優勢&#xff1b; 2、開始多需的工具 interpreter(解釋器) refactor(重構) 2、變量和注釋的基礎語法 3、輸入輸出 i 1 for i in range(1, 11): print(i, end ) 不換行打印…

jupyter notebook 實現聯邦學習模型

聯邦學習(Federated Learning)是一種機器學習框架,它允許多個參與方(例如,移動設備或服務器)在本地數據集上訓練模型,而無需將數據集中到一個位置。這有助于保護數據隱私,并允許在分布式環境中進行模型訓練。 要在Jupyter Notebook中實現聯邦學習模型,你可以遵循以下…

性能大爆炸!為你的Matomo換一個高性能的環境!

隨著我的 Matomo 越來越大&#xff0c;功能需求的增多&#xff0c;插件也變得越來越多&#xff0c;使用傳統的LNMP架構或者LAMP架構都會發現性能正在急劇下級&#xff0c;為此&#xff0c;我們發現了使用FrankenPHP&#xff08;以下簡稱FPHP&#xff09;的方案 首先&#xff0…

Android kotlin協程

說明 可代替線程整異步可控制&#xff0c;靈活 &#xff08;控制優先級&#xff0c;內存占用等&#xff09;速度快 效率高有數量上限 使用 runBlocking 一般用于測試 不建議使用GlobalScope.launch 全局的 生命周期跟隨application 不建議使用CoroutineScope(job) 用 基本使…