Linux I O多路復用(select)

2021-10-02 16:21:53 字數 4490 閱讀 3188

i/o多路復用是在多執行緒或多程序程式設計中常用技術。主要是通過select/epoll/poll三個函式支援的,就是通過記錄跟蹤每乙個sock(i/o流)的狀態來同時管理多個i/o流,i/o 多路復用技術通過把多個 i/o 的阻塞復用到同乙個 select 的阻塞上,從而使得系統在單執行緒的情況下可以同時處理多個客戶端請求

在之前我們運用多執行緒的方式也完成了乙個可以同時處理客戶端的tcp和udp的簡單伺服器

執行緒實現可以同時處理客戶端的伺服器:

引入多執行緒後,系統的執行路徑變成了多條,並且這多條執行路徑在併發執行。那麼首先程式的執行具有一定的不確定性,每次執行結果可能都會不同,因為程式交 替執行的順序和時機不同了。其次,使得某些資源的訪問出現了競爭,問題變得困難,需要資源進行同步。這會使得程式的可靠性和穩定性降低。

與傳統的多執行緒/多程序模型相比。i/o 多路復用的最大優勢是系統開銷小,系統不需要建立新的額外程序或執行緒,也不需要維護這些程序和執行緒的執行,降低了系統的維護工作量,節省了系統資源。

伺服器需要同時處理多個處於監聽狀態或者多個連線狀態的套接字;

伺服器需要同時處理多種網路協議的套接字。

作用:

select可以完成非阻塞(所謂非阻塞方式non-block,就是程序或執行緒執行此函式時不必非要等待事件的發生,一旦執行肯定返回,以返回值的不同來反映函式的執**況,如果事件發生則與阻塞方式相同,若事件沒有發生則返回乙個**來告知事件未發生,而程序或執行緒繼續執行,所以效率較高)方式工作的程式,它能夠監視我們需要監視的檔案描述符的變化情況——讀寫或是異常。

函式原型

int

select

(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds,

struct timeval *timeout)

;

所需標頭檔案

#include

/* according to earlier standards */

#include

#include

#include

返回值:

成功:(1)當沒有滿足條件的檔案描述符,且設定的timeval 監控時間超時時,select函式會返回乙個為0的值。

(2)返回相應的滿足條件的檔案描述符集中的數量

失敗:-1

引數:

nfds:監控的檔案描述符集裡最大檔案描述符加1,因為此引數會告訴核心檢測前多少個檔案描述符的狀態

readfds:監控有讀資料到達檔案描述符集合,傳入傳出引數

writefds:監控寫資料到達檔案描述符集合,傳入傳出引數

exceptfds:監控異常發生達檔案描述符集合,如帶外資料到達異常,傳入傳出引數

timeout: 結構體,定時阻塞監控時間

3種情況

1.null,永遠等下去

2.設定timeval,等待固定時間

3.設定timeval裡時間均為0,檢查描述字後立即返回,輪詢

結構體結構如下

struct timeval 

;

補充:

fd_set其實這是乙個陣列的巨集定義,實際上是一long型別的陣列,每乙個陣列元素都能與一開啟的檔案控制代碼(socket、檔案、管道、裝置等)建立聯絡,建立聯絡的工作由程式設計師完成,當呼叫select()時,由核心根據io狀態修改fd_set的內容,由此來通知執行了select()的程序哪個控制代碼可讀。

系統提供了4個巨集對描述符集進行操作

void

fd_clr

(int fd, fd_set *set)

;//把檔案描述符集合裡fd清0

intfd_isset

(int fd, fd_set *set)

;//測試檔案描述符集合裡fd是否置1

void

fd_set

(int fd, fd_set *set)

;//把檔案描述符集合裡fd位置1

void

fd_zero

(fd_set *set)

;//把檔案描述符集合裡所有位清0

引數

fd:檔案描述符

set:long型別的陣列,當呼叫select()時由核心根據io狀態修改內容,由此來通知執行了select()的程序哪個控制代碼可讀

fd_isset的返回值

成功:1

失敗:0

1.select能監聽的檔案描述符個數受限於fd_setsize,一般為1024,單純改變程序開啟的檔案描述符個數並不能改變select監聽檔案個數

2. 解決1024以下客戶端時使用select是很合適的,但如果鏈結客戶端過多,select採用的是輪詢模型,會大大降低伺服器響應效率,不應在select上投入更多精力

伺服器:

#include

#include

#include

#include

#include

#include

#define max 10

intmain()

else

struct sockaddr_in seraddr,cliaddr;

seraddr.sin_family = af_inet;

seraddr.sin_port =

htons

(5000);

seraddr.sin_addr.s_addr =

htonl

(inaddr_any)

;memset

(seraddr.sin_zero,0,

8);

socklen_t len =

sizeof

(struct sockaddr)

;int bindret =

bind

(sockfd,

(struct sockaddr *

)&seraddr,len);if

(bindret ==-1

)else

int listenret =

listen

(sockfd,max);if

(listenret ==-1

)else

fd_set read,readset;

int maxfd = sockfd;

fd_zero

(&readset)

;fd_set

(sockfd,

&readset)

;while(1

)if(fd_isset

(sockfd,

&read)

)fd_set

(confd,

&readset);if

(selectret ==1)

}char buf[

128]

;int i;

for(i = sockfd+

1;i<=maxfd;i++

)else}}

}}return0;

}

客戶端:

#include

#include

#include

#include

#include

#include

intmain()

else

struct sockaddr_in cliaddr;

cliaddr.sin_family = af_inet;

cliaddr.sin_port =

htons

(5000);

cliaddr.sin_addr.s_addr =

inet_addr

("127.0.0.1");

memset

(cliaddr.sin_zero,0,

8);int confd =

connect

(sockfd,

(struct sockaddr *

)&cliaddr,

sizeof

(struct sockaddr));

if(confd <0)

else

char buf[

128]

;while(1

)}close

(sockfd)

;return0;

}

Linux IO多路復用

一.select 函式 include include include int select int n,fd set readfds,fd set writefds,fd set exceptfds,struct timeval timeout fd clr int fd,fd set set f...

Linux IO多路復用 多路轉接

io多路復用 多路轉接 在沒有io多路復用技術前,程序在同一時間只能監控乙個io狀態 乙個檔案描述符的狀態 例如a和b兩個檔案在操作,定的順序是a前b後,那麼在a阻塞過程中 b在後面也是不能被操作的,這樣會造成資源浪費 響應緩慢。io多路復用 同時監控多個io檔案描述符狀態,如果沒有準備好的描述符 ...

Linux I O多路復用機制

i o多路復用是為了解決程序或執行緒阻塞到某個i o系統呼叫而出現的技術,使程序或執行緒不阻塞某個特定的i o系統呼叫 i o多路復用機制包括select poll epoll i o復用可以監視多個描述符,一旦某個描述符就緒,能夠通知程式進行相應的操作 它的標頭檔案和函式原型如下 includei...