linux 網路程式設計 三 非阻塞通訊select

2021-06-20 02:00:03 字數 4845 閱讀 4164

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

說明:int maxfdp是乙個整數值,是指集合中所有檔案描述符的範圍,即所有檔案描述符的最大值加1。

fd_set *readfds是指向fd_set結構的指標,這個集合中應該包括檔案描述符,我們是要監視這些檔案描述符的讀變化的,即我們關心是否可以從這些檔案中讀取資料了,如果這個集合中有乙個檔案可讀,select就會返回乙個大於0的值,表示有檔案可讀,如果沒有可讀的檔案,則根據timeout引數再判斷是否超時,若超出timeout的時間,select返回0,若發生錯誤返回負值。可以傳入null值,表示不關心任何檔案的讀變化。 

fd_set *writefds是指向fd_set結構的指標,這個集合中應該包括檔案描述符,我們是要監視這些檔案描述符的寫變化的,即我們關心是否可以向這些檔案中寫入資料了,如果這個集合中有乙個檔案可寫,select就會返回乙個大於0的值,表示有檔案可寫,如果沒有可寫的檔案,則根據timeout引數再判斷是否超時,若超出timeout的時間,select返回0,若發生錯誤返回負值。可以傳入null值,表示不關心任何檔案的寫變化。 

fd_set *errorfds同上面兩個引數的意圖,用來監視檔案錯誤異常。 

struct timeval* timeout是select的超時時間,這個引數至關重要,它可以使select處於三種狀態,第一,若將null以形參傳入,即不傳入時間結構,就是將select置於阻塞狀態,一定等到監視檔案描述符集合中某個檔案描述符發生變化為止;第二,若將時間值設為0秒0毫秒,就變成乙個純粹的非阻塞函式,不管檔案描述符是否有變化,都立刻返回繼續執行,檔案無變化返回0,有變化返回乙個正值;第三,timeout的值大於0,這就是等待的超時時間,即select在timeout時間內阻塞,超時時間之內有事件到來就返回了,否則在超時後不管怎樣一定返回,返回值同上述。 

返回值: 

負值:select錯誤 正值:某些檔案可讀寫或出錯 0:等待超時,沒有可讀寫或錯誤的檔案 

在有了select後可以寫出像樣的網路程式來!舉個簡單的例子,就是從網路上接受資料寫入乙個檔案中。 

說明套接字讀寫條件:

下列四個條件中的任何乙個滿足時,套介面準備好讀:

(1) 套介面接收緩衝區中的資料位元組數大於等於套介面接收緩衝區低潮限度的當前值。可以通過so_reviloat來設定此低潮限度。

(2)連線的讀這一半關閉,也就是接收了fin的tcp連線,

(3)套介面是乙個監聽套介面且已完成的連線數為非0.

(4)有乙個套介面錯誤等處理。

下列三個條件中的任乙個滿足時,套介面準備好寫:

(1) 套介面傳送緩衝區的可用空間位元組婁大於等於套介面傳送緩衝區低潮限度的當前值且或者(i)套介面已連線,或者(ii)套介面不要求連線。

(2)連線的寫這一半關閉,對這樣的套介面寫操作將產生訊號sigpiep。

(3)有乙個套介面錯誤待處理。

fd_zero(fd_set *fdset):清空fdset與所有檔案控制代碼的聯絡。 

fd_set(int fd, fd_set *fdset):建立檔案控制代碼fd與fdset的聯絡。 

fd_clr(int fd, fd_set *fdset):清除檔案控制代碼fd與fdset的聯絡。 

fd_isset(int fd, fdset *fdset):檢查fdset聯絡的檔案控制代碼fd是否可讀寫,>0表示可讀寫。 

[cpp]view plain

copy

/*使用select函式可以以非阻塞的方式和多個socket通訊。程式只是演示select函式的使用,即使某個連線關閉以後也不會修改當前連線數,連線數達到最大值後會終止程式。

1. 程式使用了乙個陣列fd,通訊開始後把需要通訊的多個socket描述符都放入此陣列

2. 首先生成乙個叫sock_fd的socket描述符,用於監聽埠。

3. 將sock_fd和陣列fd中不為0的描述符放入select將檢查的集合fdsr。

4. 處理fdsr中可以接收資料的連線。如果是sock_fd,表明有新連線加入,將新加入連線的socket描述符放置到fd。 */

// select_server.c

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#define myport 1234 //連線時使用的埠

#define maxcline 5 //連線佇列中的個數

#define buf_size 200

int fd[maxcline]; //連線的fd

int conn_amount; //當前的連線數

void showclient()  

printf("\n\n");  

}  int main(void)  

//設定套介面的選項 so_reuseaddr 允許在同乙個埠啟動伺服器的多個例項

// setsockopt的第二個引數sol socket 指定系統中,解釋選項的級別 普通套接字

if(setsockopt(sock_fd,sol_socket,so_reuseaddr,&yes,sizeof(int))==-1)  

server_addr.sin_family = af_inet; //主機位元組序

server_addr.sin_port = htons(myport);  

server_addr.sin_addr.s_addr = inaddr_any;//通配ip

memset(server_addr.sin_zero,'\0',sizeof(server_addr.sin_zero));  

if(bind(sock_fd,(struct sockaddr *)&server_addr,sizeof(server_addr)) == -1)  

if(listen(sock_fd,maxcline)==-1)  

printf("listen port %d\n",myport);  

fd_set fdsr; //檔案描述符集的定義

int maxsock;  

struct timeval tv;  

conn_amount =0;  

sin_size = sizeof(client_addr);  

maxsock = sock_fd;  

while(1)  

}  //如果檔案描述符中有連線請求 會做相應的處理,實現i/o的復用 多使用者的連線通訊

ret = select(maxsock +1,&fdsr,null,null,&tv);  

if(ret <0) //沒有找到有效的連線 失敗

else

if(ret ==0)// 指定的時間到,

//迴圈判斷有效的連線是否有資料到達

for(i=0;i  

//否則有相應的資料傳送過來 ,進行相應的處理

else

}  }  if(fd_isset(sock_fd,&fdsr))  

//新增新的fd 到陣列中 判斷有效的連線數是否小於最大的連線數,如果小於的話,就把新的連線套接字加入集合

if(conn_amount   

}  conn_amount++;  

printf("new connection client[%d]%s:%d\n",conn_amount,inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));  

if(new_fd > maxsock)  

}  else

}  showclient();  

}  for(i=0;i  

}  exit(0);  

}  

[cpp]view plain

copy

//客戶端的乙個簡單的實現,只是為了證實一下,伺服器端程式的正確性

//select_client.c

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#define maxdatasize 100

#define servport 1234

#define maxline 1024

int main(int argc,char *argv)  

if((host = gethostbyname(argv[1])) == null)  

if((sockfd = socket(af_inet,sock_stream,0)) == -1)  

serv_addr.sin_family = af_inet;  

serv_addr.sin_port = htons(servport);  

serv_addr.sin_addr = *((struct in_addr *)host->h_addr);  

bzero(&(serv_addr.sin_zero),8);  

if(connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(struct sockaddr)) ==-1)  

while(fgets(send,1024,stdin)!=null)  

}  close(sockfd);  

linux 網路程式設計 三 非阻塞通訊select

int select int nfds,fd set readfds,fd set writefds,fd set exceptfds,struct timeval timeout 說明 int maxfdp是乙個整數值,是指集合中所有檔案描述符的範圍,即所有檔案描述符的最大值加1。fd set r...

linux 網路程式設計 四 非阻塞通訊poll

include int poll struct pollfd fds,nfds t nfds,int timeout typedef struct pollfd pollfd t typedef unsigned long nfds t fds 是乙個struct pollfd結構型別的陣列,用於存...

Linux網路程式設計(三) IO非阻塞操作

io非阻塞操作 sock的方法不一定非得是阻塞的,也可以非阻塞的操作。有兩種方法分別為設定fcntl 和設定相應函式的引數。服務端 include include include include include include include include define bufsize 128 i...