TCP并發服務器構建

TCP并發服務器構建:

單循環服務器:服務端同一時刻只能處理單個客戶端的任務

并發服務器:服務端同一時刻能夠處理多個客戶端的任務

產生多個套接字可建立多個連接:

在這里插入圖片描述

TCP服務端并發模型:

1:使用多進程

頭文件:

#ifndef __HEAD_H__
#define __HEAD_H__#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>
#include <pthread.h>#endif

代碼

#include "head.h"#define SER_PORT  50000
#define SER_IP    "192.168.0.179"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;
}void wait_handler(int signo)
{wait(NULL);
}int main(int argc, const char *argv[])
{signal(SIGCHLD, wait_handler);struct sockaddr_in cliaddr;socklen_t clilen = sizeof(cliaddr);int sockfd = init_tcp_ser();if (sockfd < 0){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 (0 == pid){char buff[1024] = {0};while (1){memset(buff, 0, sizeof(buff));size_t cnt = recv(connfd, buff, sizeof(buff), 0);if (cnt < 0){perror("recv error");break;}else if (0 == cnt){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");cnt = send(connfd, buff, strlen(buff), 0);if (cnt < 0){perror("send error");break;}}close(connfd);}}close(sockfd);return 0;
}

2:使用多線程

#include "head.h"#define SER_PORT  50000
#define SER_IP    "192.168.0.179"int init_tcp_ser()
{int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){perror("socket error");return -1;}//允許綁定處于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){perror("bind error");return -1;}ret = listen(sockfd, 100);if (ret < 0){perror("listen error");return -1;}return sockfd;
}void *task(void *arg)
{char buff[1024] = {0};int connfd = *((int *)arg);while (1){memset(buff, 0, sizeof(buff));size_t cnt = recv(connfd, buff, sizeof(buff), 0);if (cnt < 0){perror("recv error");break;}else if (0 == cnt){printf("offline\n");break;}printf("%s\n", buff);strcat(buff, "---->ok");cnt = send(connfd, buff, strlen(buff), 0);if (cnt < 0){perror("send error");break;}}close(connfd);
}int main(int argc, const char *argv[])
{pthread_t tid;struct sockaddr_in cliaddr;socklen_t clilen = sizeof(cliaddr);int sockfd = init_tcp_ser();if (sockfd < 0){return -1;}while (1){int connfd = accept(sockfd, (struct sockaddr *)&cliaddr, &clilen);if (connfd < 0){perror("accept error");return -1;}pthread_create(&tid, NULL, task, &connfd);pthread_detach(tid);}close(sockfd);return 0;
}

線程池:

在這里插入圖片描述

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

IO多路復用:

對多個文件描述符的讀寫操作可以復用一個進程。在不創建新的進程和線程的前提下,使用一個進程實現多個文件的讀寫的同時監測。三種方式:

linux內核監測事件:
在這里插入圖片描述

1:select實現IO多路復用:

(1)創建文件描述符集合
(2)添加關注的文件描述符到集合
(3)使用select傳遞集合表給內核,內核檢測事件
(4) 當內核監測到時間時,應用層select將解除阻塞,
(5)并將獲得相關的事件結果做不同的任務處理
在這里插入圖片描述
在這里插入圖片描述
![在這里插入圖片描述](https://i-blog.csdnimg.cn/direct/5dcb7b86bd32400da9d5efe0df4f9a7f.png
在這里插入圖片描述

在這里插入圖片描述

頭文件:
#ifndef __HEAD_H__
#define __HEAD_H__#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>
#include <pthread.h>
#include <sys/select.h>/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>#endif
代碼:
#include "head.h"int main(int argc, const char *argv[])
{mkfifo("./myfifo", 0664);int fd = open("./myfifo", O_WRONLY);if (fd < 0){perror("open fifo error");return -1;}while (1){write(fd, "hello world", 11);sleep(1);}close(fd);return 0;
}
#include "head.h"int main(int argc, const char *argv[])
{char buff[1024] = {0};mkfifo("./myfifo", 0664);int fifofd = open("./myfifo", O_RDONLY);if (fifofd < 0){perror("open fifo 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)){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;
}

IO多路復用

#include "head.h"#define SER_PORT  50000
#define SER_IP    "192.168.0.179"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;
}

在這里插入圖片描述

2:poll

在這里插入圖片描述

3:epoll

在這里插入圖片描述

epoll:

1:創建文件描述符結合
2:添加關注的文件描述符
3:epoll通知內核開始進行事件監測
4:epoll返回時,獲取到達事件的結果
5:

在這里插入圖片描述
函數1:
在這里插入圖片描述
函數2:
在這里插入圖片描述
在這里插入圖片描述

在這里插入圖片描述
在這里插入圖片描述
函數3:
在這里插入圖片描述
selsect和epoll區別:EPOLL沒有文件描述符上限限制,selsect上限1024個,

在這里插入圖片描述

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

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

相關文章

優選算法-常見位運算總結

1.基礎位運算&#xff1a; >> :右移運算符&#xff1a; 邏輯右移&#xff08;無符號數&#xff09;&#xff1a;高位補 0&#xff0c;低位直接丟棄。 示例&#xff1a;8 >> 2&#xff08;二進制 1000 右移 2 位&#xff09;結果為 0010&#xff08;十進制 2&#…

記一次MySQL數據庫的操作練習

數據庫基礎使用數據庫的操作&#xff1a;1.使用命令行連接數據庫。在命令行鍵入”mysql -u root -p”命令。2.列出MySQL數據庫管理系統的數據庫列表。在命令行鍵入”show databases;”命令。3.創建數據庫。在命令行鍵入”create database database_name;”命令。使用”show dat…

C++STL-list 底層實現

目錄 一、實現框架 二、list_node節點類的模擬實現 節點構造函數 三、list_iterator迭代器的模擬實現 迭代器類的模板參數說明 構造函數 *運算符重載 運算符的重載 --運算符的重載 運算符的重載 !運算符的重載 list的模擬實現 默認成員函數 構造函數 拷貝構造函…

解決網站圖片加載慢:從架構原理到實踐

在當前的數字商業環境中&#xff0c;用戶的在線體驗至關重要。當一個潛在客戶訪問企業網站或電商平臺時&#xff0c;如果頁面加載過程遲緩&#xff0c;特別是圖片和視頻內容無法快速顯示&#xff0c;用戶的耐心會迅速耗盡。研究數據表明&#xff0c;網站加載時間與用戶跳出率和…

windows注冊表:開機自啟動程序配置

目錄 一、注冊表位置 系統范圍的開機自啟動程序 當前用戶的開機自啟動程序 二、配置步驟 三、注意事項 四、其他方法 任務計劃程序 啟動文件夾 1. 創建程序快捷方式 2. 打開 Startup 文件夾 3. 將快捷方式移動到 Startup 文件夾 4. 驗證程序是否自動啟動 注意事項 …

(11)用于無GPS導航的制圖師SLAM(一)

文章目錄 前言 1 安裝 RPLidar 和 Pixhawk 2 檢查 RPLidar 的串行端口 3 安裝更多軟件包 4 創建Catkin工作空間 5 安裝 RPLidar 節點 6 安裝 Google Cartographer 前言 本頁展示了如何使用 RPLidarA2 激光雷達(RPLidarA2 lidar)設置 ROS 和 Google Cartographer SLAM&a…

車載診斷架構 --- 基于整車功能的正向診斷需求開發

我是穿拖鞋的漢子,魔都中堅持長期主義的汽車電子工程師。 老規矩,分享一段喜歡的文字,避免自己成為高知識低文化的工程師: 做到欲望極簡,了解自己的真實欲望,不受外在潮流的影響,不盲從,不跟風。把自己的精力全部用在自己。一是去掉多余,凡事找規律,基礎是誠信;二是…

字帖生成器怎么用?電腦手機雙端操作指南

字帖生成器是一款支持電腦端和手機端的免費練字工具&#xff0c;可一鍵生成PDF格式字帖并直接打印使用。本文基于官方公開版本&#xff0c;提供無廣告、無營銷的實測操作指南。 工具基礎信息 軟件名稱&#xff1a;字帖生成器適用設備&#xff1a;Windows、安卓/鴻蒙核心功能&…

pycharm 遠程連接服務器報錯

配置遠程鏈接的時候出現報錯 Command finished with exit code 139 Execution was killed due to timeout Failed to execute command Rsync command ‘rsync’ was not found neither in local PATH nor as full executable path Starting introspection for Python… 放假前好…

局域網共享文件夾

準備工作&#xff1a; A電腦&#xff08;共享端&#xff09; B電腦&#xff08;本機&#xff09;在A電腦&#xff0c;選好要共享的目錄&#xff0c;然后右鍵屬性 > 高級共享 > 共享此文件夾 > 權限(全開)然后找到此電腦&#xff0c;右鍵&#xff0c;打開屬性&#xff…

時序數據庫全景指南:從場景選型到內核拆解

1. 什么是時序數據 時序數據&#xff08;Time-Series Data&#xff09; 是在時間上連續產生、且帶有時間戳的觀測值序列&#xff0c;典型特征&#xff1a;維度描述高并發寫百萬點/秒&#xff0c;追加為主寫多讀少90 % 查詢是降采樣或聚合時效性越新越熱&#xff0c;舊數據價值遞…

深入解析 Oracle 內存架構:駕馭 SGA 與 PGA 的性能藝術

引言&#xff1a;數據庫的心臟與大腦如果說磁盤上的數據文件是 Oracle 數據庫的“身體”&#xff0c;是永久存儲的基石&#xff0c;那么內存結構就是其“心臟與大腦”。它負責所有計算活動的發生&#xff0c;決定了數據泵送的速度與效率。一個配置得當、運行順暢的內存體系&…

竣工驗收備案識別技術:通過AI和OCR實現智能化文檔處理,提升效率與準確性,推動建筑行業數字化轉型。

竣工驗收備案是建設工程項目投入使用的最終法定程序&#xff0c;是確保工程符合規劃、質量、消防、環保等各項要求的核心關口。傳統的備案流程依賴大量紙質文檔和人工審核&#xff0c;效率低下且易出錯。隨著人工智能與大數據技術的崛起&#xff0c;竣工驗收備案識別技術應運而…

76 最小覆蓋子串

76 最小覆蓋子串 文章目錄76 最小覆蓋子串1 題目2 解答1 題目 給你一個字符串 s 、一個字符串 t 。返回 s 中涵蓋 t 所有字符的最小子串。如果 s 中不存在涵蓋 t 所有字符的子串&#xff0c;則返回空字符串 "" 。 注意&#xff1a; 對于 t 中重復字符&#xff0c;…

趣味學Rust基礎篇(變量與可變性)

這篇文章將用通俗的比喻和清晰的邏輯&#xff0c;帶你深入理解 Rust 變量背后的核心思想&#xff0c;讓你不僅“會用”&#xff0c;更能“明白為什么”。 Rust 的“盒子哲學”&#xff1a;變量、可變性、常量與隱藏 想象一下&#xff0c;Rust 里的變量就像一個個盒子。你把值&a…

2025年- H100-Lc208--912.排序數組(快速選擇排序)--Java版

1.題目2.思路 快速選擇排序的平均時間復雜度是O&#xff08;nlogn&#xff09;&#xff0c;最壞時間復雜度是O&#xff08;n^2&#xff09;&#xff0c;最好的時間復雜度是O&#xff08;nlogn&#xff09;&#xff0c;空間復雜度是O&#xff08;nlogn&#xff09;。 排序算法中…

解決 pdf.mjs 因 MIME 類型錯誤導致的模塊加載失敗問題

Mozilla PDF.js V4 開始&#xff0c;它官方分發確實只提供了 ESM 模塊&#xff08;.mjs&#xff09;&#xff0c;沒有以前的 pdf.js、pdf.worker.js UMD 版本了。 這個問題本質上是 瀏覽器要求以 application/javascript MIME 類型加載 ES Module&#xff0c;而你引入的 pdf.mj…

STM32八大模式

前言&#xff1a;STM32存在八大模式&#xff0c;分別如下推挽輸出&#xff0c;開漏輸出&#xff0c;復用推挽輸出&#xff0c;復用開漏輸出浮空輸入&#xff0c;上拉輸入&#xff0c;下拉輸入&#xff0c;模擬輸入STM32標準IO結構圖如下&#xff1a;其中如下電路為保護電路&…

OpenCV4.X庫功能全解---個人筆記

文章目錄前言1.Core核心功能1.1 基本數據類型和結構&#xff1a;1.2 數組操作&#xff1a;1.3 數學函數&#xff1a;1.4 隨機數生成&#xff1a;1.5 線性代數運算&#xff1a;1.6 常用數據結構和算法&#xff1a;1.7 XML/YAML文件讀寫&#xff1a;1.8 錯誤處理&#xff1a;1.9時…

代碼隨想錄刷題Day44

二叉搜索樹的最近公共祖先 這道題&#xff0c;可以沿用二叉樹的最近公共祖先的求法進行求解&#xff0c;也就是root判斷-左右子樹遞歸求LCA-根據左右子樹的LCA結果返回值這一套。 但是&#xff0c;如果要用上搜索二叉樹的有序性這個信息的話&#xff0c;就可以直接在遞歸時候確…