多客戶端 - 服務器結構-實操

實現2個客戶端之間互相聊天
要求:
1、服務器使用 select 模型實現接受多個客戶端連接,以及轉發消息
2、客戶端要求:使用 poll 模型解決 技能夠 read 讀取服務器發來的消息,又能夠scanf讀取鍵盤輸入的信息
3、客戶端服務器不允許開啟額外線程和進程

服務器代碼 (select模型)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/select.h>#define MAX_CLIENTS 10
#define BUFFER_SIZE 1024int main(int argc, char *argv[]) {if (argc != 2) {printf("Usage: %s <port>\n", argv[0]);return 1;}int server_fd, new_socket, client_sockets[MAX_CLIENTS];struct sockaddr_in address;int opt = 1;int addrlen = sizeof(address);char buffer[BUFFER_SIZE] = {0};// 初始化客戶端socket數組for (int i = 0; i < MAX_CLIENTS; i++) {client_sockets[i] = 0;}// 創建socketif ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {perror("socket failed");exit(EXIT_FAILURE);}// 設置socket選項if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {perror("setsockopt");exit(EXIT_FAILURE);}address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(atoi(argv[1]));// 綁定socketif (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {perror("bind failed");exit(EXIT_FAILURE);}// 監聽if (listen(server_fd, 3) < 0) {perror("listen");exit(EXIT_FAILURE);}printf("Server started on port %d\n", atoi(argv[1]));fd_set readfds;int max_sd, activity;while (1) {FD_ZERO(&readfds);FD_SET(server_fd, &readfds);max_sd = server_fd;// 添加客戶端socket到集合for (int i = 0; i < MAX_CLIENTS; i++) {if (client_sockets[i] > 0) {FD_SET(client_sockets[i], &readfds);}if (client_sockets[i] > max_sd) {max_sd = client_sockets[i];}}// 使用select等待活動activity = select(max_sd + 1, &readfds, NULL, NULL, NULL);if ((activity < 0) && (errno != EINTR)) {perror("select error");}// 檢查新連接if (FD_ISSET(server_fd, &readfds)) {if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {perror("accept");exit(EXIT_FAILURE);}printf("New connection, socket fd: %d, ip: %s, port: %d\n",new_socket, inet_ntoa(address.sin_addr), ntohs(address.sin_port));// 添加新socket到數組for (int i = 0; i < MAX_CLIENTS; i++) {if (client_sockets[i] == 0) {client_sockets[i] = new_socket;printf("Adding to list of sockets as %d\n", i);break;}}}// 檢查客戶端數據for (int i = 0; i < MAX_CLIENTS; i++) {int sd = client_sockets[i];if (FD_ISSET(sd, &readfds)) {int valread = read(sd, buffer, BUFFER_SIZE);if (valread == 0) {// 客戶端斷開連接getpeername(sd, (struct sockaddr*)&address, (socklen_t*)&addrlen);printf("Host disconnected, ip: %s, port: %d\n",inet_ntoa(address.sin_addr), ntohs(address.sin_port));close(sd);client_sockets[i] = 0;} else {// 轉發消息給所有客戶端buffer[valread] = '\0';printf("Forwarding message: %s\n", buffer);for (int j = 0; j < MAX_CLIENTS; j++) {if (client_sockets[j] > 0 && client_sockets[j] != sd) {send(client_sockets[j], buffer, strlen(buffer), 0);}}}}}}return 0;
}

客戶端代碼 (poll模型)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <poll.h>#define BUFFER_SIZE 1024int main(int argc, char *argv[]) {if (argc != 3) {printf("Usage: %s <ip> <port>\n", argv[0]);return 1;}int sock = 0;struct sockaddr_in serv_addr;char buffer[BUFFER_SIZE] = {0};struct pollfd fds[2];// 創建socketif ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {perror("socket creation failed");return -1;}serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(atoi(argv[2]));// 轉換IP地址if (inet_pton(AF_INET, argv[1], &serv_addr.sin_addr) <= 0) {perror("invalid address");return -1;}// 連接服務器if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {perror("connection failed");return -1;}printf("Connected to server\n");// 設置poll結構fds[0].fd = STDIN_FILENO;    // 標準輸入fds[0].events = POLLIN;fds[1].fd = sock;            // socketfds[1].events = POLLIN;while (1) {int ret = poll(fds, 2, -1); // 無限等待if (ret == -1) {perror("poll error");break;}// 檢查鍵盤輸入if (fds[0].revents & POLLIN) {memset(buffer, 0, BUFFER_SIZE);if (fgets(buffer, BUFFER_SIZE, stdin) == NULL) {break;}// 發送消息到服務器send(sock, buffer, strlen(buffer), 0);}// 檢查服務器消息if (fds[1].revents & POLLIN) {memset(buffer, 0, BUFFER_SIZE);int len = recv(sock, buffer, BUFFER_SIZE, 0);if (len <= 0) {printf("Server disconnected\n");break;}printf("Received: %s", buffer);}}close(sock);return 0;
}

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

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

相關文章

iOS高級開發工程師面試——Objective-C 語言特性

iOS高級開發工程師面試——Objective-C 語言特性 一、多態二、繼承三、代理(Delegate)1. 代理為什么用 weak 修飾呢?block和代理的區別?四、通知(NSNotificationCenter)五、KVC (Key-value Coding)六、屬性七、`@property` [?pr?p?ti]的本質是什么?ivar 、 setter …

MMpretrain 中的 LinearClsHead 結構與優化

LinearClsHead 結構與優化 一、LinearClsHead 核心結構 在 MMPretrain 中&#xff0c;LinearClsHead 是一個簡潔高效的分類頭&#xff0c;其核心結構如下&#xff1a; class LinearClsHead(BaseModule):def __init__(self,num_classes, # 類別數量in_channels, # 輸入…

Spring 學習筆記

1.Spring AOP 怎么實現的AOP 即面向切面編程&#xff0c;是通過代理實現的&#xff0c;主要分為靜態代理和動態代理&#xff0c;靜態代理就是在程序運行前就已經指定并聲明了代理類和增強邏輯&#xff0c;運行時就已經被編譯為字節碼文件了&#xff0c;而動態代理則是在運行過程…

【CVPR2024】計算機視覺|InceptionNeXt:速度與精度齊飛的CNN架構

論文地址&#xff1a;http://arxiv.org/pdf/2303.16900v3 代碼地址&#xff1a;https://github.com/sail-sg/inceptionnext 關注UP CV縫合怪&#xff0c;分享最計算機視覺新即插即用模塊&#xff0c;并提供配套的論文資料與代碼。 https://space.bilibili.com/473764881 摘要…

7.15 窗口函數 | 二分 | 位運算 | 字符串dp

lc3316. 字符串dpdp多開一行一列后&#xff0c;注意原字符串下標映射dp[n][m] &#xff08; n 是source長度&#xff0c; m 是pattern長度&#xff09;兩重循環填表for i 1-nfor j 0-m三種狀態轉移1.不選 dp i jdp i-1 j2.不選if tag, dp[i][j]3.if(s ip j) 選&#xff0c;dp i…

Spring原理揭秘--初識AOP

我們知道軟件開發一直在追求高效&#xff0c;易維護&#xff0c;易擴展的特性方式。在面向過程編程到面向對象編程的歷程中&#xff0c;程序的開發有了非常大的進步。但是oop的方式缺依然存在著一些缺點。oop的方式可以將業務進行很好的分解和封裝使其模塊化&#xff0c;但是卻…

Provider模式:軟件架構中的“供應商“設計哲學

文章目錄Provider模式&#xff1a;軟件架構中的“供應商“設計哲學什么是Provider模式&#xff1f;經典應用場景1. 配置管理Provider2. 數據訪問Provider4. 消息隊列ProviderProvider模式的優勢1. 解耦合實際項目中的應用Provider模式的最佳實踐1. 命名約定2. 接口設計原則3. 錯…

LTspic下載,幫助及演示電路

1.下載 LTspice是一款強大高效的免費SPICE仿真器軟件、原理圖采集和波形觀測器&#xff0c;為改善模擬電路的仿真提供增強功能和模型。其原理圖捕獲圖形界面使您能夠探測原理圖并生成仿真結果&#xff0c;這些結果可以通過內置波形查看器進一步觀察分析。 鏈接&#xff1a; …

位置編碼/絕對位置編碼/相對位置編碼/Rope原理+公式詳細推導及代碼實現

文章目錄1. 位置編碼概述1.1 為什么需要位置編碼&#xff1f;2. 絕對位置編碼 (Absolute Position Encoding)2.1 原理2.2 數學公式2.3 代碼實現2.4 代碼與公式的對應關系2.5 特性與優勢2.6 可學習的絕對位置編碼3. 相對位置編碼 (Relative Position Encoding)3.1 原理3.2 數學公…

網絡安全初級第一次作業

一&#xff0c;docker搭建和掛載vpm 1.安裝 Docker apt-get install docker.io docker-compose 2.創建文件 mkdir /etc/docker.service.d vim /etc/docker.service.d/http-proxy.conf 3.改寫文件配置 [Service] Environment"HTTP_PROXYhttp://192.168.10.103:7890…

交換類排序的C語言實現

交換類排序包括冒泡排序和快速排序兩種。冒泡排序基本介紹冒泡排序是通過重復比較相鄰元素并交換位置實現排序。其核心思想是每一輪遍歷將未排序序列中的最大&#xff08;或最小&#xff09;元素"浮動"到正確位置&#xff0c;類似氣泡上升。基本過程是從序列起始位置…

嵌入式 Linux開發環境構建之Source Insight 的安裝和使用

目錄 一、Source Insight 的安裝 二、Source Insight 使用 一、Source Insight 的安裝 這個軟件是代碼編輯和查看軟件&#xff0c;打開開發板光盤軟件&#xff0c;然后右鍵選擇以管理員身份運行這個安裝包。在彈出來的安裝向導里面點擊 next &#xff0c;如下圖所示。這里選擇…

【字節跳動】數據挖掘面試題0016:解釋AUC的定義,它解決了什么問題,優缺點是什么,并說出工業界如何計算AUC。

文章大綱 AUC(Area Under the Curve)詳解一、定義:AUC是什么?二、解決了什么問題?三、優缺點分析四、工業界大規模計算AUC的方法1. 標準計算(小數據)2. 工業級大規模計算方案3.工業界最佳實踐4.工業界方案選型建議總結:AUC的本質AUC(Area Under the Curve)詳解 一、…

Python后端項目之:我為什么使用pdm+uv

在試用了一段時間的uv和pdm之后&#xff0c;上個月(2025.06)開始&#xff0c;逐步把用了幾年的poetry替換成了pdmuv&#xff08;pipx install pdm uv && pdm config use_uv true) ## 為什么poetry -> pdm: 1. 通過ssh連接到服務器并使用poetry shell激活虛擬環境之…

鴻蒙Next開發,配置Navigation的Route

1. 通過router_map.json配置文件進行 創建頁面配置router_map.json {"routerMap": [{"name": "StateExamplePage","pageSourceFile": "src/main/ets/pages/state/StateExamplePage.ets","buildFunction": "P…

在 GitHub 上創建私有倉庫

一、在 GitHub 上創建私有倉庫打開 GitHub官網 并登錄。點擊右上角的 “” → 選擇 “New repository”。填寫以下內容&#xff1a; Repository name&#xff1a;倉庫名稱&#xff0c;例如 my-private-repo。Description&#xff1a;可選&#xff0c;倉庫描述。Visibility&…

量產技巧之RK3588 Android12默認移除導航欄狀態欄?

本文介紹使用源碼編譯默認去掉導航欄/狀態欄方法,以觸覺智能EVB3588開發板演示&#xff0c;Android12系統&#xff0c;搭載了瑞芯微RK3588芯片&#xff0c;該開發板是核心板加底板設計&#xff0c;音視頻接口、通信接口等各類接口一應俱全&#xff0c;可幫助企業提高產品開發效…

Conda 安裝與配置詳解及常見問題解決

《Conda 安裝與配置詳解及常見問題解決》 安裝 Conda 有兩種主流方式&#xff0c;分別是安裝 Miniconda&#xff08;輕量級&#xff09;和 Anaconda&#xff08;包含常用數據科學包&#xff09;。下面為你詳細介紹安裝步驟和注意要點。 一、安裝 Miniconda&#xff08;推薦&a…

Linux ——lastb定時備份清理

lastb 命令顯示的是系統中 /var/log/btmp 文件中的SSH 登錄失敗記錄。你可以像處理 wtmp 那樣&#xff0c;對 btmp 文件進行備份與清理。? 一、備份 lastb 數據cp /var/log/btmp /var/log/btmp.backup.$(date %F)會保存為如 /var/log/btmp.backup.2025-07-14? 二、清空 lastb…

自定義類型 - 聯合體與枚舉(百度筆試題算法優化)

目錄一、聯合體1.1 聯合體類型的聲明1.2 聯合體的特點1.3 相同成員的結構體和聯合體對比1.4 聯合體大小的計算1.5 聯合練習二、枚舉類型2.1 枚舉類型的聲明2.2 枚舉類型的優點總結一、聯合體 1.1 聯合體類型的聲明 像結構體一樣&#xff0c;聯合體也是由一個或者多個成員構成…