Linux應用軟件編程---網絡編程(TCP并發服務器構建:[ 多進程、多線程、select ])

TCP并發服務器構建

一、服務器

? ??單循環服務器:服務端同一時刻只能處理一個客戶端的任務(TCP)
并發服務器:服務端同一時刻可以處理多個客戶端的任務(UDP)

二、TCP服務端并發模型

1、多進程

? ? ?進程資源開銷大,安全性高。

? ? ?以下是一個實現多進程TCP服務端代碼:

#define SER_PORT 62300
#define SER_IP "192.168.0.165"int init_tcp_ser()
{int sockfd = socket(AF_INET, SOCK_STREAM, 0);if(sockfd < 0){perror("socket error");return 0;}struct sockaddr_in seraddr;seraddr.sin_family = AF_INET;seraddr.sin_port = htons(SER_PORT);seraddr.sin_addr.s_addr = inet_addr(SER_IP);int ret = bind(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));if(ret < 0){printf("bind error");return -1;}int cnt = listen(sockfd, 100);if(cnt < 0){perror("listen error");return -1;}return sockfd;
}void wait_handler(int signo)
{wait(NULL);
}int main(int argc, char *argv[])
{signal(SIGCHLD, wait_handler);struct sockaddr_in cliaddr;socklen_t clilen = sizeof(cliaddr);int sockfd = init_tcp_ser();if(sockfd < 0){perror("init_tcp_ser error");return -1;}while(1){int connfd = accept(sockfd, (struct sockaddr *)&cliaddr, &clilen); if(connfd < 0){perror("accept error");return -1;}pid_t pid = fork();if(pid > 0){}else if(pid == 0){char buff[1024] = {0};while(1){memset(buff, 0, sizeof(buff));ssize_t ret = recv(connfd, buff, sizeof(buff), 0);if(ret < 0){perror("send error");return -1;}else if(ret == 0){printf("[%s : %d]: offline!\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));break;}printf("[%s : %d]: %s\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port), buff);strcat(buff, "----OK");ssize_t cnt = send(connfd, buff, strlen(buff), 0);if(cnt < 0){perror("send error");break;}}   close(connfd);}}close(sockfd);return 0;
}

2、多線程

? ? ?線程相對與進程資源開銷小,相同資源環境下,并發量比進程大。

? ? ?以下是一個實現多線程TCP服務端代碼:

#include "head.h"#define SER_PORT 62300
#define SER_IP "192.168.0.165"int init_tcp_ser()
{int sockfd = socket(AF_INET, SOCK_STREAM, 0);if(sockfd < 0){perror("socket error");return 0;}//允許綁定處于TIME_WAIT狀態的地址,避免端口占用問題:int optval = 1;setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));struct sockaddr_in seraddr;seraddr.sin_family = AF_INET;seraddr.sin_port = htons(SER_PORT);seraddr.sin_addr.s_addr = inet_addr(SER_IP);int ret = bind(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));if(ret < 0){printf("bind error");return -1;}int cnt = listen(sockfd, 100);if(cnt < 0){perror("listen error");return -1;}return sockfd;
}void *task(void *sug)
{int connfd = *(int *)sug;char buff[1024] = {0};while(1){memset(buff, 0, sizeof(buff));ssize_t ret = recv(connfd, buff, sizeof(buff), 0);if(ret < 0){perror("send error");break;}else if(ret == 0){printf("[%s : %d]: offline!\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));break;}printf("[%s : %d]: %s\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port), buff);strcat(buff, "----OK");ssize_t cnt = send(connfd, buff, strlen(buff), 0);if(cnt < 0){perror("send error");break;}}   close(connfd);
}int main(int argc, char *argv[])
{struct sockaddr_in cliaddr;socklen_t clilen = sizeof(cliaddr);int sockfd = init_tcp_ser();if(sockfd < 0){perror("init_tcp_ser error");return -1;}while(1){int connfd = accept(sockfd, (struct sockaddr *)&cliaddr, &clilen); if(connfd < 0){perror("accept error");return -1;}pthread_t tid;int fd = pthread_create(&tid, NULL, task, &connfd);if(fd < 0){perror("thread create error");return -1;}  pthread_detach(tid);}close(sockfd);return 0;
}

3、線程池

? ? ?為了解決多線程或者多進程模型,在服務器運行過程,頻繁創建和銷毀線程(進程)帶來的時間消耗問題。
基于生產者和消費者編程模型,以及任務隊列等,實現的一套多線程框架。

4. ?IO多路復用

? ? 1)概念

? ? ?對多個文件描述符的讀寫可以復用一個進程。
在不創建新的進程和線程的前提下,使用一個進程實現對多個文件讀寫的同時監測。
阻塞IO模式:

? ? 2)方式

? ? ? ? 實現方式有 select、poll、epoll 三種。

5、select 實現IO多路復用

? ? 1)實現步驟

? ??(1)創建文件描述符集合? ? ?fd_set
(2)添加關注的文件描述符到集合? ? ?FD_SET
(3)使用 select 傳遞集合表給內核,內核開始監測事件? ? select()
(4)當內核監測到事件時,應用層select將解除阻塞,并獲得相關的事件結果
(5)根據 select 返回的結果做不同的任務處理

? ? 2)select 的宏

????????將集合清0:void FD_ZERO(fd_set *set);
向集合中添加文件描述符:void FD_SET(int fd, fd_set *set);
從集合中移除文件描述符:void FD_CLR(int fd, fd_set *set);
檢查文件描述符是否在集合中:int ?FD_ISSET(int fd, fd_set *set);

? ? 3)select() 函數接口

?int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);

功能:傳遞文件描述符結合表給內核并等待獲取事件結果
參數:
nfds : 關注的最大文件描述符+1
readfds:讀事件的文件描述符集合
writefds:寫事件的文件描述符集合
exceptfds:其他事件的文件描述符集合
timeout:設置select監測時的超時時間
若為NULL : 不設置超時時間(select一直阻塞等待)

返回值:
成功:返回內核監測的到達事件的個數
失敗:-1
0 : 超時時間到達,但沒有事件發生,則返回0

? ? 4)應用示例

? ? ? ? (1)通過select函數構建多路復用,實現管道和終端的讀

????????管道向服務端寫的代碼:

int main(void)
{mkfifo("./myfifo", 0664);int fd = open("./myfifo", O_WRONLY);if(fd < 0){perror("open error");return -1;}while(1){write(fd, "hello world", 11);sleep(1);}close(fd);return 0;
}

? ? ? ? 讀的代碼:

int main(void)
{char buff[1024] = {0};mkfifo("./myfifo", 0664);int fifofd = open("./myfifo", O_RDONLY);if(fifofd < 0){perror("open error");return -1;}//1、創建文件描述符集合fd_set rdfds;fd_set rdfdstmp;//2、清空文件描述符集合表FD_ZERO(&rdfds);//初始化...集//3、添加關注的文件描述符到集合中FD_SET(0, &rdfds);//添加int maxfd = 0;FD_SET(fifofd, &rdfds);maxfd = maxfd > fifofd ? maxfd : fifofd;while(1){rdfdstmp = rdfds;//4、傳遞集合表給內核并等待返回到達事件的結果int cnt = select(maxfd+1, &rdfdstmp, NULL, NULL, NULL);if(cnt < 0){perror("select error");return -1;}if(FD_ISSET(0, &rdfdstmp))//檢查文件描述符0是否在集合中{fgets(buff, sizeof(buff), stdin);//0printf("STDIN: %s\n", buff);}if(FD_ISSET(fifofd, &rdfdstmp)){memset(buff, 0, sizeof(buff));read(fifofd, buff, sizeof(buff));printf("FIFO: %s\n", buff);}}close(fifofd);return 0;
}

? ? ? ? (2)使用select實現TCP服務端IO多路復用代碼

#define SER_PORT  50000
#define SER_IP    "192.168.0.165"int init_tcp_ser()
{int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){perror("socket error");return -1;}struct sockaddr_in seraddr;seraddr.sin_family = AF_INET;seraddr.sin_port = htons(SER_PORT);seraddr.sin_addr.s_addr = inet_addr(SER_IP);int ret = bind(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));if (ret < 0){perror("bind error");return -1;}ret = listen(sockfd, 100);if (ret < 0){perror("listen error");return -1;}return sockfd;
}int main(int argc, const char *argv[])
{char buff[1024] = {0};struct sockaddr_in cliaddr;socklen_t clilen = sizeof(cliaddr);int sockfd = init_tcp_ser();if (sockfd < 0){return -1;}//1. 創建文件描述符集合fd_set rdfds;fd_set rdfdstmp;FD_ZERO(&rdfds);//2. 添加關注的文件描述符到集合FD_SET(sockfd, &rdfds);int maxfd = sockfd;while (1){rdfdstmp = rdfds;//3. 傳遞集合到內核,并等待返回監測結果int cnt = select(maxfd+1, &rdfdstmp, NULL, NULL, NULL);if (cnt < 0){perror("select error");return -1;}//4. 是否有監聽套接字事件到達 ----》三次握手已完成,可以acceptif (FD_ISSET(sockfd, &rdfdstmp)){int connfd = accept(sockfd, (struct sockaddr *)&cliaddr, &clilen);if (connfd < 0){perror("accept error");return -1;}FD_SET(connfd, &rdfds);maxfd = maxfd > connfd ? maxfd : connfd;}//5. 是否有通訊套接字事件到達for (int i = sockfd+1; i <= maxfd; i++){if (FD_ISSET(i, &rdfdstmp)){memset(buff, 0, sizeof(buff));ssize_t cnt = recv(i, buff, sizeof(buff), 0);if (cnt < 0){perror("recv error");FD_CLR(i, &rdfds);close(i);continue;}else if (0 == cnt){FD_CLR(i, &rdfds);close(i);continue;}printf("%s\n", buff);strcat(buff, "--->ok");cnt = send(i, buff, strlen(buff), 0);if (cnt < 0){perror("send error");FD_CLR(i, &rdfds);close(i);continue;}}}	}close(sockfd);return 0;
}

【END】

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

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

相關文章

重構審計體驗!批量生成報表項目底稿的憑證檢查表

在審計工作中&#xff0c;我們通過序時賬或其他審計軟件篩選導出的憑證列表&#xff0c;要如何快速分發給各個報表項目底稿的憑證檢查表呢&#xff1f; “TB工具箱2025”正式上線“批量生成憑證表”的功能&#xff0c;通過一些巧妙的設計&#xff0c;使其具備高度的通用性&…

【c++進階系列】:萬字詳解二叉搜索樹(附源碼實現)

&#x1f525; 本文專欄&#xff1a;c &#x1f338;作者主頁&#xff1a;努力努力再努力wz &#x1f4aa; 今日博客勵志語錄&#xff1a; 你可以走得慢&#xff0c;但別回頭 1.概念 二叉搜索樹&#xff0c;從其名字我們就能知道該數據結構是一個特殊的二叉樹&#xff0c;而二…

通過web服務做橫向移動

環境配置邊緣主機(win10)&#xff1a;192.168.237.140 10.10.90.128內網主機(win7)&#xff1a;10.10.90.129 web服務 -- upload-labs攻擊機&#xff1a;vps&#xff08;120.26.114.196&#xff09;windows10windows7假設已經拿下邊緣主機win10&#xff0c;vshell上線ipconfig查…

把CentOS 7默認yum源改成騰訊云鏡像

步驟計劃&#xff1a; 備份原有CentOS-Base.repo文件&#xff0c;防止配置出錯可恢復 下載騰訊云提供的CentOS 7鏡像源配置文件&#xff08;對應CentOS-Base.repo&#xff09; 清理并生成yum緩存&#xff0c;使新源生效 具體命令 # 備份原有源 sudo mv /etc/yum.repos.d/C…

歐盟《人工智能法案》生效一年主要實施進展概覽(二)

文章目錄前言三、《關于禁止的人工智能實踐指南》1. 整體適用2. 禁止的人工智能系統具體介紹&#xff08;1&#xff09;有害操縱和欺騙類及對脆弱性的有害利用類&#xff08;2&#xff09;社會評分類&#xff08;3&#xff09;個人刑事犯罪風險評估和預測類&#xff08;4&#…

私域電商新范式:開源AI智能名片鏈動2+1模式S2B2C商城小程序賦能傳統行業流量轉化

摘要&#xff1a;本文聚焦私域電商領域&#xff0c;指出其并非僅局限于快消品等傳統電商行業&#xff0c;多數傳統行業同樣面臨私域流量利用難題。傳統行業手握私域流量或優質流量入口&#xff0c;卻不知如何有效轉化&#xff0c;陷入流量焦慮。在此背景下&#xff0c;開源AI智…

Axios 整理常用形式及涉及的參數

一、axios get請求 //形如 axios.get(url[, config]).then(response > {// 處理響應}).catch(error > {// 處理錯誤}); //無 config 的情況下&#xff0c; axios.get(https://api.example.com/data).then(response > {// 處理響應}) .catch(error > {// 處理錯誤})…

深度學習---卷積神經網絡CNN

卷積神經網絡CNN&#xff08;Convolutional Neural Networks&#xff09;一、圖像原理圖像在計算機中是一堆按順序排列的數字&#xff0c;數值為0到255。0表示最暗&#xff0c;255表示最亮。上圖是只有黑白顏色的灰度圖&#xff0c;而更普遍的圖片表達方式是RGB顏色模型&#x…

日志輸出觸發的死鎖問題排查記錄

現象描述 錯誤日志&#xff1a; Found one Java-level deadlock:"http-nio-8083-exec-106":waiting for ownable synchronizer 0x00000005cbfa6b90, (a java.util.concurrent.locks.ReentrantLock$NonfairSync),which is held by "http-nio-8083-exec-10" …

UNIX網絡編程筆記:高級套接字編程20-25

廣播通信&#xff1a;局域網內的高效信息傳播 在局域網通信場景中&#xff0c;廣播是一種高效的一對多信息傳播方式 。它無需為每個接收者單獨建立連接&#xff0c;能一次性將消息送達網段內所有目標&#xff0c;廣泛應用于服務發現、網絡通知等場景。以下從基礎原理到實踐應用…

React Native核心技術深度解析_Trip Footprints

React Native 框架詳細技術解析 作為前端開發者&#xff0c;理解React Native需要從Web開發的角度出發&#xff0c;了解其獨特之處和技術實現。 &#x1f3af; React Native 核心概念 什么是React Native&#xff1f; React Native是Facebook開發的跨平臺移動應用開發框架&…

預算管理的“數字圍欄“:如何用實時預警終結行政費用超支

作為公司行政主管&#xff0c;每年最讓我忐忑的時刻不是年終總結&#xff0c;而是季度財務分析會。當CFO皺著眉頭指出行政費用又超支時&#xff0c;那種如坐針氈的感覺至今難忘。行政預算就像一匹難以馴服的野馬&#xff0c;明明已經嚴加管控&#xff0c;卻總在年底給我們"…

NTLM哈希深度解析:從原理到安全實踐

NTLM哈希深度解析&#xff1a;從原理到安全實踐作為一名白帽子黑客&#xff0c;深入理解NTLM哈希機制對保障企業網絡安全至關重要。1. NTLM哈希概述 NTLM&#xff08;New Technology LAN Manager&#xff09;是微軟推出的一套身份驗證協議套件&#xff0c;用于在Windows網絡中驗…

4-3.Python 數據容器 - 集合 set(集合 set 概述、集合的定義、集合的遍歷、集合的常用方法)

集合 set 概述集合用于存儲一系列元素集合存儲的元素是無序的&#xff0c;不支持索引集合存儲的元素是不可以重復的集合存儲的元素可以是不同類型的&#xff0c;例如、數字、字符串、甚至是其他集合集合是可變的&#xff0c;在程序運行時可以添加、刪除其中的元素一、集合的定義…

驗證碼請求與緩存問題解決方案

驗證碼請求與緩存問題解決方案 1.問題描述 請求驗證碼圖片未變化&#xff0c;且未監聽到新請求的問題。 2.問題分析 這個問題的根本原因通常是瀏覽器緩存機制導致的 - 瀏覽器會緩存相同URL的圖片&#xff0c;導致第二次請求時直接從緩存讀取而不發送新請求。 3.解決方案思路 在…

安卓接入通義千問AI的實現記錄

官網&#xff1a;https://help.aliyun.com/zh/model-studio/use-qwen-by-calling-api#b1320a1664b9a 創建網絡請求 創建一個BaseNetworkApi基類用于實現各種攔截器等。 abstract class BaseNetworkApi {fun <T> getApi(serviceClass: Class<T>, baseUrl: String…

Linux 命令瀏覽文件內容

Linux 命令瀏覽文件內容 1. cat 查看文件的所有內容1.1 -n 顯示行號1.2 -b 顯示沒有空行的行號2. head 前10行標準輸出2.1 -c 輸出每行第一個字符2.2 -n 指定行數3. tail 顯示文件的最后 10 行數據3.1 -c 顯示指定字符3.2 -n 指定行數3.3 顯示追加內容4. more 分頁顯示文件內容…

UVa11607 Cutting Cakes

UVa11607 Cutting Cakes題目鏈接題意分析AC 代碼題目鏈接 UVa11607 Cutting Cakes 題意 平面上有n&#xff08;n≤1 500&#xff09;個點&#xff0c;其中沒有3 點共線。另外有m&#xff08;m≤700 000&#xff09;條直線&#xff0c;你的任務是對于每條直線&#xff0c;輸出3…

[e3nn] 等變神經網絡 | 線性層o3.Linear | 非線性nn.Gate

第4章&#xff1a;等變神經網絡模塊 歡迎回來&#xff5e; 在我們探索e3nn的旅程中&#xff0c;我們已經揭示了一些基本概念&#xff1a; 在第1章&#xff1a;不可約表示&#xff08;Irreps&#xff09;中&#xff0c;我們學習了Irreps作為等變數據的標簽&#xff0c;告訴我們數…

共享云服務器替代傳統電腦做三維設計會卡頓嗎

與傳統本地工作站相比&#xff0c;云服務器在硬件配置、協作效率和成本控制方面具有明顯優勢&#xff0c;但設計師們比較關心的主要問題始終是&#xff1a;使用共享云服務器進行三維設計會出現卡頓嗎&#xff1f;這取決于硬件配置、網絡環境、軟件優化及使用場景等多方面因素。…