IO多路復用實現并發服務器

一.select函數

select 的調用注意事項
在使用 select 函數時,需要注意以下幾個關鍵點:

1. 參數的修改與拷貝
? ?readfds 等參數是結果參數 :
? ?select 函數會直接修改傳入的 fd_set(如 readfds、writefds 和 exceptfds)。
? ?為了保留原始監聽集合,通常會定義一個備份集合(如 allread_fdset),并將它的拷貝傳遞給 select。
?? ?示例:
?? ?fd_set allread_fdset, readfds;
?? ?FD_ZERO(&allread_fdset);
?? ?FD_SET(fd1, &allread_fdset);
?? ?FD_SET(fd2, &allread_fdset);

?? ?readfds = allread_fdset; // 拷貝到臨時集合
?? ?select(..., &readfds, ...);
2. 計算 nfds

?? ?nfds 是最大文件描述符值 + 1 :
?? ?在新增監聽句柄時,更新 nfds 較為簡單。
?? ?在減少監聽句柄時,更新 nfds 較為復雜:
?? ?如果需要精確計算,可以通過遍歷或維護一個最大堆等數據結構來找到第二大的文件描述符。
?? ?或者,可以選擇忽略 nfds 的更新,但可能導致性能下降。
?? ?
?? ?
3. 超時參數 timeout
?? ?timeout 的含義 :
?? ?如果為 NULL,表示阻塞等待,直到有事件發生。
?? ?如果指向的時間為 0,表示非阻塞模式。
?? ?如果指定超時時間,則 select 會在超時后返回。
?? ?注意:Linux 實現中,select 返回時會修改 timeout 為剩余時間 :
?? ?如果需要重復使用 timeout,需要重新初始化。
?? ?
4. 返回值的處理
?? ?返回值的意義 :
?? ?-1:表示錯誤。
?? ?0:表示超時時間到,沒有事件發生。
?? ?正數:表示監聽到的事件總數(包括可讀、可寫和異常事件)。
?? ?優化事件處理 :
?? ?可以利用返回值避免不必要的檢查。例如,如果返回值為 1,并且已經在可讀集合中處理了一個事件,則無需再檢查可寫和異常集合。

select 的缺點
?? ?盡管 select 是一種經典的 I/O 多路復用機制,但它存在以下顯著缺點:

?? ?1. 文件描述符數量限制
?? ??? ?FD_SETSIZE 的限制 :
?? ??? ?每個 fd_set 最多只能監聽 FD_SETSIZE 個文件描述符(在 Linux 上通常是 1024)。
?? ??? ?這一限制使得 select 不適合高并發場景。
?? ??? ?
?? ?2. 遍歷效率低
?? ??? ?需要逐一檢查文件描述符 :
?? ??? ?返回的 fd_set 是一個位圖,應用程序需要對所有監聽的文件描述符逐一調用 FD_ISSET 來判斷是否就緒。
?? ??? ?示例:

?? ??? ?for (int i = 0; i < nfds; i++) {
?? ??? ??? ?if (FD_ISSET(i, &readfds)) {
?? ??? ??? ??? ?// 處理可讀事件
?? ??? ??? ?}
?? ??? ?}
3. nfds 的效率問題
?? ?select 的實現方式 :
?? ?select 內部會遍歷從 0 到 nfds-1 的所有文件描述符,判斷每個描述符是否是關心的,并檢查是否有事件發生。
?? ?即使只監聽少數幾個文件描述符(如 0 和 1000),select 仍然需要遍歷 1001 個描述符,導致效率低下。


總結
優點
? ? 簡單易用,跨平臺支持廣泛。
缺點
?? ?文件描述符數量受限 :最多只能監聽 FD_SETSIZE 個文件描述符。
?? ?遍歷效率低 ? ? ? ? :需要逐一檢查文件描述符,增加了開銷。
?? ?nfds 的問題 ? ? ? ?:即使監聽的文件描述符稀疏分布,select 仍需遍歷所有小于 nfds 的描述符。
這些缺點促使了更高效的 I/O 多路復用機制(如 poll 和 epoll)的出現,尤其是在高并發場景下,epoll 成為了更優的選擇。

【1】管道select

【2】tcp服務器select

二.poll函數

poll?
? ?針對select 做了改進?
? ?底層實現 --- 用的是數組?
? ?poll --- 鏈表?
? ?poll 引入了事件機制?
? ?
? ?1. 遍歷?
? ?2. poll 需要在 用戶空間 和 內核空間 來回拷貝?

epoll?
? ?三種多路IO操作中最高效


? ?
?

三.epoll函數

3. epoll
int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

typedef union epoll_data {
?? ?void *ptr;
?? ?int fd;
?? ?__uint32_t u32;
?? ?__uint64_t u64;
} epoll_data_t;

struct epoll_event {
?? ?__uint32_t events; ? ? ?/* Epoll events */
?? ?epoll_data_t data; ? ? ?/* User data variable */
};
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);


epoll 解決了select和poll的幾個性能上的缺陷:
① 不限制監聽的描述符個數(poll也是),只受進程打開描述符總數的限制;
② 監聽性能不隨著監聽描述 符數的增加而增加,是O(1) 的,
? 不再是輪詢描述符來探測事件,而是由描述符主動上報事件; //事件機制的?
③ 使用共享內存的方式,不在用戶和內核之間反復傳遞監聽的描述 符信息;
④ 返回參數中就是觸發事件的列表,不用再遍歷輸入事件表查詢各個事件是否被觸發

------------------------------------------

epoll顯著提高性能的前提是:
監聽大量描述符,
并且每次觸發事件的描述符文件非常少。
epoll的另外區別是:
①epoll創建了描述符,記得close;
②支持水平觸發和邊沿觸發。

epoll使用注意事項:
//epoll_create
① int epoll_create(int size); ? ?//創建epoll文件描述符
參數size并不是限制了epoll所能監聽的描述符最大個數,
只是對內核初始分配內部數據結構的一個建議。
返回是epoll描述符。-1表示創建失敗。


//epoll_ctl
② int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); ? ?//epoll文件描述符的控制接口
功能:
? ? ?epoll_ctl控制對指定描述符fd執行op操作,event是與fd關聯的監聽事件。
參數:
? ?@epfd --- epoll對象?
? ?@op?
?? ??? ?op操作有三種:
?? ??? ?
?? ??? ?添加EPOLL_CTL_ADD,
?? ??? ?
?? ??? ?刪除EPOLL_CTL_DEL,
?? ??? ?
?? ??? ?修改EPOLL_CTL_MOD。
?? ??? ?
?? ?分別添加、刪除和修改對fd的監聽事件。
?? ?重復添加fd會怎樣(event相同或不相同):
?? ?添加失敗(errno:17, File exists)
?? ?刪除和修改不存在的fd會怎樣:
?? ?刪除或修改失敗(errno:9,Bad file descriptor)

? @fd -- 關心的fd?
??
??
event是與監聽的fd相關聯的事件信息,event->events描述了要監聽的事件類型,有以下類型:
//事件類型:
EPOLLIN ? ? ? ?可讀
EPOLLOUT ? ? ? 可寫
EPOLLRDHUP ? ? 套接口對端close或shutdown寫,在ET模式下比較有用
EPOLLPRI ? ? ? 緊急數據可讀
EPOLLERR ? ? ? 異常條件
EPOLLHUP ? ? ? 掛起,EPOLLERR和EPOLLHUP始終由epoll_wait監聽,不需要用戶設置
EPOLLET ? ? ? ?邊沿觸發模式,在描述符狀態跳變時才上報監聽事件。(監聽默認都是LT模式)(ET+非阻塞模式)
EPOLLONESHOT ? 只一次有效,設置oneshot標記,描述符在觸發一次事件之后自動失效(fd還被監聽),
? ? ? ? ? ? ? ?不會再上報任何事件,直到使用EPOLL_CTL_MOD重新激活,
? ? ? ? ? ? ? ?設置新的監聽事件為止(可不可以和之前的事件一樣?)。

event->data是個共用體,可以存放和fd綁定的描述符信息,
比如就存放描述符本身fd,或者一個結構體信息,包括fd,ip,port等等。

在epoll_wait返回時,只會返回一個event列表,需要從列表元素中獲取fd等信息。
返回值:
? ? ? ? 返回0表示控制成功,
?? ??? ?返回-1表示失敗。

③ int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
//等待epfd上的io事件,最多返回maxevents個事件
timeout = -1 的行為是block;
timeout = ?0 是立即返回

④ epoll監聽ET事件時,fd必須是非阻塞套接口。
比如監聽可讀事件,當ET上報可讀后,需要一直讀fd直到遇到EAGAIN錯誤為止,以免遺留數據在緩沖區中。
如果fd是阻塞的,則會讀到阻塞了。
EAGAIN錯誤對于非阻塞套接口來說不是錯誤,只是說沒有數據可讀或者沒有空間可寫。
EWOULDBLOCK就是EAGAIN,值都是11。
selset/poll/epoll的LT模式監聽的fd可以是阻塞模式的。

⑤ 多路復用監聽io事件時,如果對某個套接口監聽可寫事件,總是會返回可寫而事實上可能沒有數據要寫。
處理方法:
①只有在有數據要寫時才把要寫的套接口加入 監聽列表中,數據全部寫完之后從監聽列表中刪除它;
②在有數據寫時,首先嘗試直接寫,當直接寫沒有把數據全部寫入發送緩沖區時再把這個套接口加入可寫事件 監聽列表。
(這種方式效率較高,需要套接口是非阻塞的,前一種方式可以是阻塞的嗎?)
可以是阻塞的。

四. 特點和區別

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

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

相關文章

_二級繼電器程控放大倍數自動設置

簡介 在開發項目中&#xff0c;有時會遇到需要使用程控放大的情況&#xff0c;如果沒有opa那種可編程放大器&#xff0c;那么就需要通過繼電器來控制放大倍數。而在繼電器程控中&#xff0c;常用的是二級程控&#xff0c;三級程控相較于二級就復雜了許多。 在二級程控中&#x…

電腦總顯示串口正在被占用處理方法

1.現象 在嵌入式開發過程中&#xff0c;有很多情況下要使用串口調試&#xff0c;其中485/422/232轉usb串口是非常常見的做法。 根據協議&#xff0c;接口芯片不同&#xff0c;需要安裝對應的驅動程序&#xff0c;比如ch340&#xff0c;cp2102&#xff0c;CDM212364等驅動。可…

優雅拼接字符串:StringJoiner 的完整指南

在Java開發中&#xff0c;字符串拼接是高頻操作。無論是日志格式化、構建CSV數據&#xff0c;還是生成動態SQL&#xff0c;開發者常需處理分隔符、前綴和后綴的組合。傳統的StringBuilder雖然靈活&#xff0c;但代碼冗余且易出錯。Java 8推出的StringJoiner類&#xff0c;以簡潔…

LabVIEW閉環控制系統硬件選型與實時性能

在LabVIEW閉環控制系統的開發中&#xff0c;硬件選型直接影響系統的實時性、精度與穩定性。需綜合考慮數據采集速度&#xff08;采樣率、接口帶寬&#xff09;、計算延遲&#xff08;算法復雜度、處理器性能&#xff09;、輸出響應時間&#xff08;執行器延遲、控制周期&#x…

Hive的架構

1. 概念 Hive 是建立在 Hadoop 上的數據倉庫工具&#xff0c;旨在簡化大規模數據集的查詢與管理。它通過類 SQL 語言&#xff08;HiveQL&#xff09;將結構化數據映射為 Hadoop 的 MapReduce&#xff0c;適合離線批處理&#xff0c;尤其適用于數據倉庫場景。 2. 數據模型 表&a…

深入解析:Linux中KVM虛擬化技術

這篇文章將深入分析Linux中虛擬化技術的實現----KVM技術&#xff0c;從KVM技術的簡介、技術架構、以及虛擬機和宿主機交互的重要處理邏輯出發&#xff0c;深入探究KVM技術的實現。 一、KVM簡介&#xff1a; 首先&#xff0c;我們先查看一下KVM架構&#xff0c;看看它的整體工…

golang學習筆記——go語言安裝及系統環境變量設置

文章目錄 go語言安裝go envgo getgoproxy測試安裝 Go 插件安裝 Go 插件依賴工具參考資料用戶環境變量和系統環境變量用戶環境變量系統環境變量示例設置環境變量的步驟設置用戶環境變量設置系統環境變量 驗證環境變量總結 2024年最火的5大Go框架1. Gin&#xff1a;高并發接口的“…

3.6c語言

#define _CRT_SECURE_NO_WARNINGS #include <math.h> #include <stdio.h> int main() {int sum 0,i,j;for (j 1; j < 1000; j){sum 0;for (i 1; i < j; i){if (j % i 0){sum i;} }if (sum j){printf("%d是完數\n", j);}}return 0; }#de…

【TI】如何更改 CCS20.1.0 的 WORKSPACE 默認路徑

參考鏈接&#xff1a; 如何更改 CCS Theia 中工作區的默認位置&#xff1f;- Code Composer Studio 論壇 - Code Composer Studio?? - TI E2E 支持論壇 --- How to change the default location for the workspace in CCS Theia? - Code Composer Studio forum - Code Comp…

Vue3中動態Ref的魔法:綁定與妙用

前言 在Vue 3的開發過程中,動態綁定Ref是一項非常實用的技術,特別是在處理復雜組件結構和動態數據時。通過動態綁定Ref,我們可以更靈活地訪問和操作DOM元素或組件實例,實現更高效的交互和狀態管理。本文將詳細介紹如何在Vue 3中實現動態Ref的綁定,并通過實例展示其妙用。…

CarPlanner:用于自動駕駛大規模強化學習的一致性自回歸軌跡規劃

25年2月來自浙大和菜鳥網絡的論文“CarPlanner: Consistent Auto-regressive Trajectory Planning for Large-scale Reinforcement Learning in Autonomous Driving”。 軌跡規劃對于自動駕駛至關重要&#xff0c;可確保在復雜環境中安全高效地導航。雖然最近基于學習的方法&a…

VS Code連接服務器教程

VS Code是什么 VS Code&#xff08;全稱 Visual Studio Code&#xff09;是一款由微軟推出的免費、開源、跨平臺的代碼編輯神器。VS Code 支持 所有主流操作系統&#xff0c;擁有強大的功能和靈活的擴展性。 官網&#xff1a;https://code.visualstudio.com/插件市場&#xff1…

【JavaWeb】Web基礎概念

文章目錄 1、服務器與客戶端2、服務器端應用程序3、請求和響應4、項目的邏輯構成5、架構5.1 概念5.2 發展演變歷程單一架構分布式架構 5.3 單一架構技術體系 6、本階段技術體系 1、服務器與客戶端 ①線下的服務器與客戶端 ②線上的服務器與客戶端 2、服務器端應用程序 我…

安徽省考計算機專業科目2025(持續更新)

目錄 第一部分 計算機科學技術基礎 第一章 計算機及其應用基礎知識 1.1 計算機的特點、分類及其應用 1.2 信息編碼與數據表示&#xff1b;數制及其轉換方法&#xff1b;算術運算和邏輯運算的過程 第一部分 計算機科學技術基礎 第一章 計算機及其應用基礎知識 1.1 計算機…

前端知識點---路由模式-實例模式和單例模式(ts)

在 ArkTS&#xff08;Ark UI 框架&#xff09;中&#xff0c;路由實例模式&#xff08;Standard Instance Mode&#xff09;主要用于管理頁面跳轉。當創建一個新頁面時&#xff0c;可以選擇標準實例模式&#xff08;Standard Mode&#xff09;或單實例模式&#xff08;Single M…

【leetcode hot 100 73】矩陣置零

解法一&#xff1a;&#xff08;使用兩個標記變量&#xff09;用矩陣的第一行和第一列代替方法一中的兩個標記數組&#xff08;col、row[ ]&#xff1a;第幾列、行出現0&#xff09;&#xff0c;以達到 O(1) 的額外空間。 這樣會導致原數組的第一行和第一列被修改&#xff0c;…

【十三】Golang 通道

&#x1f4a2;歡迎來到張胤塵的開源技術站 &#x1f4a5;開源如江河&#xff0c;匯聚眾志成。代碼似星辰&#xff0c;照亮行征程。開源精神長&#xff0c;傳承永不忘。攜手共前行&#xff0c;未來更輝煌&#x1f4a5; 文章目錄 通道通道聲明初始化緩沖機制無緩沖通道代碼示例 帶…

【JAVA架構師成長之路】【電商系統實戰】第12集:秒殺系統性能優化實戰(CAN + Nginx + Sentinel)

30分鐘課程&#xff1a;秒殺系統性能優化實戰&#xff08;CDN Nginx Sentinel&#xff09; 課程目標 掌握靜態資源 CDN 加速的配置與優化策略。通過 Nginx 實現負載均衡&#xff0c;提升系統橫向擴展能力。使用 Sentinel 實現服務降級&#xff0c;保障核心鏈路穩定性。 課程…

K8S學習之基礎十八:k8s的灰度發布和金絲雀部署

灰度發布 逐步擴大新版本的發布范圍&#xff0c;從少量用戶逐步擴展到全體用戶。 特點是分階段發布、持續監控、逐步擴展 適合需要逐步驗證和降低風險的更新 金絲雀部署 將新版本先部署到一小部分用戶或服務器&#xff0c;觀察其表現&#xff0c;再決定是否全面推廣。 特點&…

畢業項目推薦:基于yolov8/yolo11的蘋果葉片病害檢測識別系統(python+卷積神經網絡)

文章目錄 概要一、整體資源介紹技術要點功能展示&#xff1a;功能1 支持單張圖片識別功能2 支持遍歷文件夾識別功能3 支持識別視頻文件功能4 支持攝像頭識別功能5 支持結果文件導出&#xff08;xls格式&#xff09;功能6 支持切換檢測到的目標查看 二、數據集三、算法介紹1. YO…