多路復用select與poll

2021-05-22 17:43:50 字數 4109 閱讀 5117

華清遠見嵌入式學院

講師。在unix/linux中有4中io模型,分別為:

1、 阻塞io

2、 非阻塞io

3、 io多路復用

4、 訊號驅動io

這幾種io模型,阻塞io是最長用到的,並且操作相對簡單,但是缺點在於效率低下,尤其是在,同時操作多個io的時候,不能隨時的處理各個io操作。而非阻塞io可以解決這個問題,但是同樣也存在的問題,因為使用非阻塞io模型的時候,就需要對每個io操作進行輪訓操作,而實際上輪空的機率是很大的,多以非阻塞io模型是在那種輪空機率相對較小的的時候才會使用。因為輪訓是會占用相當多的cpu時間片的。基於這種考慮多路復用模型變產生了。

多路復用模型是對多個io操作進行檢測,返回可操作集合,這樣就可以對其進行操作了。這樣就避免了阻塞io不能隨時處理各個io和非阻塞占用系統資源的確定。下面就多路復用中兩個常用的系統呼叫select和poll進行簡單的說明。

1、 select

select函式的原型為:

#include

#include

#include

#include

int select(int nfds,

fd_set *readfds,

fd_set *writefds,

fd_set *exceptfds,

struct timeval *timeout);

select的使用需要維護三類檔案描述符集合,分別是:

readfds:用於存放我們要檢測的可讀的檔案描述符。

writefds:用於存放我們要檢測的可寫的檔案描述符。

exceptfds:用於存放我們要檢測的是否發生異常的檔案描述符。

在使用select的時候需要注意,在呼叫select後者幾個集合就會變化,變為是操作的集合,即可讀寫或發生異常,所以在呼叫select之前需要儲存以前的集合。

系統為我們提供了下面四個巨集來操作這些檔案描述符集合:

void fd_set(int fd, fd_set *set);

void fd_clr(int fd, fd_set *set);

i int fd_isset(int fd, fd_set *set);

void fd_zero(fd_set *set);

其中fd_set用來將乙個檔案描述符加入到檔案描述符集合裡,fd_clr是刪除,fd_isset是判斷檔案描述符是否在這個集合裡,而fd_zero是將這個集合清零。

下面我們以乙個簡單的例子來說明select的使用。

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define n 64

int main(int argc, char *argv)

int i, servsock, connfd, maxfd;

char buf[n];

fd_set rdfd,rdfd1;

struct sockaddr_in servaddr;

if((servsock = socket(pf_inet, sock_stream, 0)) < 0)

memset(&servaddr, 0, sizeof(servaddr));

servaddr.sin_family = pf_inet;

servaddr.sin_addr.s_addr = inet_addr("192.168.1.203");

servaddr.sin_port = htons(8889);

if(bind(servsock, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)

listen(servsock, 5);

maxfd = servsock;

fd_zero(&rdfd1);

fd_set(0, &rdfd1);

fd_set(servsock, &rdfd1);

for(;;)

for(i = 0; i <= maxfd; i++)

else if(i == servsock)}}

}return 0;

}上面這段程式在select會阻塞,這個時候我們可以定義乙個時間結構體變數,如下:

struct timeval timeout;

timeval的原型為:

struct timeval ;

這個變數可以提供乙個微秒級的時間,我們可以使用這個作為超時處理。使用方式就是把這個變數作為select系統呼叫的最後乙個引數。

2、 poll

poll的原型為:

#include

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

poll的使用不需要分別維護幾個表,只需要維護乙個結構體陣列,這個結構體為:

struct pollfd ;

這個結構體幾個成員分別是我們要監測的檔案描述符,和我們請求的事件及最後返回的事件。

poll事件的型別為:

pollin there is data to read.

pollpri there is urgent data to read .

pollout writing now will not block.

pollerr error condition (output only).

pollhup hang up (output only).

pollnval invalid request: fd not open (output only).

上面這些事件最下面三種在events中沒有用的,只能在revents中才能出現。我們可以呼叫poll並且檢視每個檔案描述符的返回狀態進行相應的操作。

下面以乙個簡單的實力說明poll的使用:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define open_max openmax

#define bufsize 1024

int main(int argc, char **argv)

int openmax = getdtablesize();

int listensock, connsock;

struct sockaddr_in servaddr;

struct pollfd fds[open_max];

int i, count = 0, ready, reval;

char readbuf[bufsize];

for(i = 0; i < open_max; i++)

if((listensock = socket(af_inet, sock_stream, 0)) < 0)

memset(&servaddr, 0, sizeof(servaddr));

servaddr.sin_family = af_inet;

servaddr.sin_addr.s_addr = inet_addr(argv[1]);

servaddr.sin_port = htons(atoi(argv[2]));

if(bind(listensock, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)

listen(listensock, 5);

fds[0].fd = 0;

fds[0].events = pollin;

count++;

fds[1].fd = listensock;

fds[1].events = pollin;

count++;

for(;;)

else if(fds[i].fd == listensock)

else}}

}}return 0;

}

多路復用select與poll

華清遠見嵌入式學院 講師。在unix linux中有4中io模型,分別為 1 阻塞io 2 非阻塞io 3 io多路復用 4 訊號驅動io 這幾種io模型,阻塞io是最長用到的,並且操作相對簡單,但是缺點在於效率低下,尤其是在,同時操作多個io的時候,不能隨時的處理各個io操作。而非阻塞io可以解決...

IO多路復用 select與poll

1.阻塞與非阻塞 阻塞方式block,程序執行到這一函式時必須等待事件發生,如果沒發生,就一直阻塞函式不能返回 非阻塞 non block 程序或執行緒執行不必等待事件發生一旦執行肯定返回以不停返回返回值來反應函式執 況 select就是這樣監視描述符的變化 2.select模型 兩結構體 stru...

I O多路復用 poll

函式結構 int poll struct pollfd fds,nfds t nfds,int timeout 引數 返回值 和select一模一樣 events和revents events 關注事件 讀就緒 寫就緒 異常 輸入的時候起作用 revents 輸出結果,輸出的時候起作用 輸入輸出引數...