linux 網路編程【三】 非阻塞通訊select

來源:互聯網
上載者:User
函式宣告select函數

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表示可讀寫。 
程式碼範例(轉載)

轉載自點擊開啟連結
伺服器端

/*使用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 <stdio.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/time.h>#include <netinet/in.h>#include <arpa/inet.h>#define MYPORT 1234 //串連時使用的連接埠#define MAXCLINE 5 //串連隊列中的個數#define BUF_SIZE 200int fd[MAXCLINE]; //串連的fdint conn_amount; //當前的串連數void showclient(){int i;printf("client amount:%d\n",conn_amount);for(i=0;i<MAXCLINE;i++){printf("[%d]:%d ",i,fd[i]);}printf("\n\n");}int main(void){int sock_fd,new_fd; //監聽通訊端 串連通訊端struct sockaddr_in server_addr; // 伺服器的地址資訊struct sockaddr_in client_addr; //用戶端的地址資訊socklen_t sin_size;int yes = 1;char buf[BUF_SIZE];int ret;int i;//建立sock_fd通訊端if((sock_fd = socket(AF_INET,SOCK_STREAM,0))==-1){perror("setsockopt");exit(1);}//設定套介面的選項 SO_REUSEADDR 允許在同一個連接埠啟動伺服器的多個執行個體// setsockopt的第二個參數SOL SOCKET 指定系統中,解釋選項的層級 普通通訊端if(setsockopt(sock_fd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int))==-1){perror("setsockopt error \n");exit(1);}server_addr.sin_family = AF_INET; //主機位元組序server_addr.sin_port = htons(MYPORT);server_addr.sin_addr.s_addr = INADDR_ANY;//通配IPmemset(server_addr.sin_zero,'\0',sizeof(server_addr.sin_zero));if(bind(sock_fd,(struct sockaddr *)&server_addr,sizeof(server_addr)) == -1){perror("bind error!\n");exit(1);}if(listen(sock_fd,MAXCLINE)==-1){perror("listen error!\n");exit(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){//初始設定檔案描述符集合FD_ZERO(&fdsr); //清除描述符集FD_SET(sock_fd,&fdsr); //把sock_fd加入描述符集//逾時的設定tv.tv_sec = 30;tv.tv_usec =0;//添加活動的串連for(i=0;i<MAXCLINE;i++){if(fd[i]!=0){FD_SET(fd[i],&fdsr);}}//如果檔案描述符中有串連請求 會做相應的處理,實現I/O的複用 多使用者的串連通訊ret = select(maxsock +1,&fdsr,NULL,NULL,&tv);if(ret <0) //沒有找到有效串連 失敗{perror("select error!\n");break;}else if(ret ==0)// 指定的時間到,{printf("timeout \n");continue;}//迴圈判斷有效串連是否有資料到達for(i=0;i<conn_amount;i++){if(FD_ISSET(fd[i],&fdsr)){ret = recv(fd[i],buf,sizeof(buf),0);if(ret <=0) //用戶端串連關閉,清除檔案描述符集中的相應的位{printf("client[%d] close\n",i);close(fd[i]);FD_CLR(fd[i],&fdsr);fd[i]=0;conn_amount--;}//否則有相應的資料發送過來 ,進行相應的處理else{if(ret <BUF_SIZE)memset(&buf[ret],'\0',1);printf("client[%d] send:%s\n",i,buf);}}}if(FD_ISSET(sock_fd,&fdsr)){new_fd = accept(sock_fd,(struct sockaddr *)&client_addr,&sin_size);if(new_fd <=0){perror("accept error\n");continue;}//添加新的fd 到數組中 判斷有效串連數是否小於最大的串連數,如果小於的話,就把新的串連通訊端加入集合if(conn_amount <MAXCLINE){for(i=0;i< MAXCLINE;i++){if(fd[i]==0){fd[i] = new_fd;break;}}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){maxsock = new_fd;}}else{printf("max connections arrive ,exit\n");send(new_fd,"bye",4,0);close(new_fd);continue;}}showclient();}for(i=0;i<MAXCLINE;i++){if(fd[i]!=0){close(fd[i]);}}exit(0);}
用戶端
//用戶端的一個簡單的實現,只是為了證實一下,伺服器端程式的正確性//select_client.c#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <netdb.h>#include <sys/types.h>#include <netinet/in.h>#include <sys/socket.h>#include <sys/types.h>#define MAXDATASIZE 100#define SERVPORT 1234#define MAXLINE 1024int main(int argc,char *argv[]){int sockfd,sendbytes;// char send[MAXLINE];char send[MAXLINE];char buf[MAXDATASIZE];struct hostent *host;struct sockaddr_in serv_addr;if(argc <2){fprintf(stderr,"Please enter the server's hostname\n");exit(1);}if((host = gethostbyname(argv[1])) == NULL){perror("gethostbyname");exit(1);}if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1){perror("socket error \n");exit(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){perror("connect \n");exit(1);}while(fgets(send,1024,stdin)!=NULL){if((sendbytes = write(sockfd,send,100)) ==-1){perror("send error \n");exit(1);}}close(sockfd);}
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.