socket 的selecte用法

socket select()用法

一、winsock中
#include <winsock.h>

原型

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

nfds:本參數忽略,僅起到兼容作用。
   readfds:(可選)指針,指向一組等待可讀性檢查的套接口。
   writefds:(可選)指針,指向一組等待可寫性檢查的套接口。
   exceptfds:(可選)指針,指向一組等待錯誤檢查的套接口。
   timeout:select()最多等待時間,對阻塞操作則爲NULL。

註釋:
   本函數用於確定一個或多個套接口的狀態。對每一個套接口,調用者可查詢它的可讀性、可寫性及錯誤狀態信息。用fd_set結構來表示一組等待檢查的套接 口。在調用返回時,這個結構存有滿足一定條件的套接口組的子集,並且select()返回滿足條件的套接口的數目。有一組宏可用於對fd_set的操作, 這些宏與Berkeley Unix軟件中的兼容,但內部的表達是完全不同的。
   readfds參數標識等待可讀性檢查的套接口。如果該套接口正處於監聽listen()狀態,則若有連接請求到達,該套接口便被標識爲可讀,這樣一個 accept()調用保證可以無阻塞完成。對其他套接口而言,可讀性意味着有排隊數據供讀取。或者對於SOCK_STREAM類型套接口來說,相對於該套 接口的虛套接口已關閉,於是recv()或recvfrom()操作均能無阻塞完成。如果虛電路被“優雅地”中止,則recv()不讀取數據立即返回;如 果虛電路被強制復位,則recv()將以WSAECONNRESET錯誤立即返回。如果SO_OOBINLINE選項被設置,則將檢查帶外數據是否存在 (參見setsockopt())。
   writefds參數標識等待可寫性檢查的套接口。如果一個套接口正在connect()連接(非阻塞),可寫性意味着連接順利建立。如果套接口並未處於 connect()調用中,可寫性意味着send()和sendto()調用將無阻塞完成。〔但並未指出這個保證在多長時間內有效,特別是在多線程環境 中〕。
   exceptfds參數標識等待帶外數據存在性或意味錯誤條件檢查的套接口。請注意如果設置了SO_OOBINLINE選項爲假FALSE,則只能用這種 方法來檢查帶外數據的存在與否。對於SO_STREAM類型套接口,遠端造成的連接中止和KEEPALIVE錯誤都將被作爲意味出錯。如果套接口正在進行 連接connect()(非阻塞方式),則連接試圖的失敗將會表現在exceptfds參數中。
   如果對readfds、writefds或exceptfds中任一個組類不感興趣,可將它置爲空NULL。
   在winsock.h頭文件中共定義了四個宏來操作描述字集。FD_SETSIZE變量用於確定一個集合中最多有多少描述字(FD_SETSIZE缺省值 爲64,可在包含winsock.h前用#define FD_SETSIZE來改變該值)。對於內部表示,fd_set被表示成一個套接口的隊列,最後一個有效元素的後續元素爲INVAL_SOCKET。宏 爲:
   FD_CLR(s,*set):從集合set中刪除描述字s。
   FD_ISSET(s,*set):若s爲集合中一員,非零;否則爲零。
   FD_SET(s,*set):向集合添加描述字s。
   FD_ZERO(*set):將set初始化爲空集NULL。
   timeout參數控制select()完成的時間。若timeout參數爲空指針,則select()將一直阻塞到有一個描述字滿足條件。否則的 話,timeout指向一個timeval結構,其中指定了select()調用在返回前等待多長時間。如果timeval爲{0,0},則 select()立即返回,這可用於探詢所選套接口的狀態。如果處於這種狀態,則select()調用可認爲是非阻塞的,且一切適用於非阻塞調用的假設都 適用於它。舉例來說,阻塞鉤子函數不應被調用,且WINDOWS套接口實現不應yield。

返回值:
   select()調用返回處於就緒狀態並且已經包含在fd_set結構中的描述字總數;如果超時則返回0;否則的話,返回SOCKET_ERROR錯誤,應用程序可通過WSAGetLastError()獲取相應錯誤代碼。

錯誤代碼:
   WSANOTINITIALISED:在使用此API之前應首先成功地調用WSAStartup()。
   WSAENETDOWN:WINDOWS套接口實現檢測到網絡子系統失效。
   WSAEINVAL:超時時間值非法。
   WSAEINTR:通過一個WSACancelBlockingCall()來取消一個(阻塞的)調用。
   WSAEINPROGRESS:一個阻塞的WINDOWS套接口調用正在運行中。
   WSAENOTSOCK:描述字集合中包含有非套接口的元素。

範例 :

sock= socket(AF_INET,SOCK_STREAM,0);

struct sockaddr_in addr;      //告訴sock 應該再什麼地方licence
memset(&addr,0,sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_port=htons(11111);   //端口啦
addr.sin_addr.s_addr=htonl(INADDR_ANY);        //在本機的所有ip上開始監聽

bind (sock,(sockaddr *)&addr,sizeof(addr));//bind....

listen(sock,5);                   //最大5個隊列

SOCKET socka;                    //這個用來接受一個連接
fd_set rfd;                     // 描述符集 這個將用來測試有沒有一個可用的連接
struct timeval timeout;

FD_ZERO(&rfd);                     //總是這樣先清空一個描述符集

timeout.tv_sec=60;                //等下select用到這個
timeout.tv_usec=0;

u_long ul=1;

ioctlsocket(sock,FIONBIO,&ul);    //用非阻塞的連接

//現在開始用select
FD_SET(sock,&rfd);    //把sock放入要測試的描述符集 就是說把sock放入了rfd裏面 這樣下一步調用select對rfd進行測試的時候就會測試sock了(因爲我們將sock放入的rdf) 一個描述符集可以包含多個被測試的描述符,
if(select(sock+1,&rfd,0,0, &timeout)==0)
{ //這個大括號接上面的,返回0那麼就超過了timeout預定的時間

//處理....

}

if(FD_ISSET(sock,&rfd))
{      //有一個描述符準備好了

socka=accept(sock,0,0);     //一個用來測試讀 一個用來測試寫

FD_ZERO(&rfd);

FD_ZERO(&wfd);

FD_SET(socka,&rfd);//把socka放入讀描述符集

FD_SET(sockb,&rfd);//把sockb放入讀描述符集

FD_SET(socka,&wfd);把socka放入寫描述符集

FD_SET(sockb,&wfd);把sockb放入寫描述符集

if(SOCKET_ERROR!=select(0,&rfd,&wfd,0,0))      //測試這兩個描述符集,永不超時 其中rfd只用來測試讀 wfd只用來測試寫

{      //沒有錯誤

if(FD_ISSET(socka,&rfd))    //socka可讀

{...}

if(FD_ISSET(sockb,&rfd)   //sockb可讀

{...}

if(FD_ISSET(socka,&wfd) //socka 可寫

{...}

if(FD_ISSET(sockb,&wfd) //sockb可寫

{...}

}

 

二、linux c中

select(I/O多工機制)


表頭文件

#i nclude<sys/time.h>
#i nclude<sys/types.h>
#i nclude<unistd.h>

定義函數

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

函數說明

select()用來等待文件描述詞狀態的改變。參數n代表最大的文件描述詞加1,參數readfds、writefds 和exceptfds 稱爲描述詞組,是用來回傳該描述詞的讀,寫或例外的狀況。底下的宏提供了處理這三種描述詞組的方式:
FD_CLR(inr fd,fd_set* set);用來清除描述詞組set中相關fd 的位
FD_ISSET(int fd,fd_set *set);用來測試描述詞組set中相關fd 的位是否爲真
FD_SET(int fd,fd_set*set);用來設置描述詞組set中相關fd的位
FD_ZERO(fd_set *set); 用來清除描述詞組set的全部位

參數

timeout爲結構timeval,用來設置select()的等待時間,其結構定義如下
struct timeval
{
time_t tv_sec;
time_t tv_usec;
};

返回值

如果參數timeout設爲NULL則表示select()沒有timeout。

錯誤代碼

執行成功則返回文件描述詞狀態已改變的個數,如果返回0代表在描述詞狀態改變前已超過timeout時間,當有錯誤發生時則返回-1,錯誤原因存於errno,此時參數readfds,writefds,exceptfds和timeout的值變成不可預測。
EBADF 文件描述詞爲無效的或該文件已關閉
EINTR 此調用被信號所中斷
EINVAL 參數n 爲負值。
ENOMEM 核心內存不足

範例

常見的程序片段:fs_set readset;
FD_ZERO(&readset);
FD_SET(fd,&readset);
select(fd+1,&readset,NULL,NULL,NULL);
if(FD_ISSET(fd,readset){……}

下面是linux環境下select的一個簡單用法

#i nclude <sys/time.h>
#i nclude <stdio.h>
#i nclude <sys/types.h>
#i nclude <sys/stat.h>
#i nclude <fcntl.h>
#i nclude <assert.h>

int main ()
{
int keyboard;
int ret,i;
char c;
fd_set readfd;
struct timeval timeout;
keyboard = open("/dev/tty",O_RDONLY | O_NONBLOCK);
assert(keyboard>0);
while(1)
    {
timeout.tv_sec=1;
timeout.tv_usec=0;
FD_ZERO(&readfd);
FD_SET(keyboard,&readfd);
ret=select(keyboard+1,&readfd,NULL,NULL,&timeout);
if(FD_ISSET(keyboard,&readfd))
    {
      i=read(keyboard,&c,1);
          if('/n'==c)
          continue;
      printf("hehethe input is %c/n",c);
    
       if ('q'==c)
      break;
      }
}}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章