網路通訊——select()機制

來源:互聯網
上載者:User

 

背景知識分析:

 1. fd_set 結構體

  fd_set是檔案控制代碼的集合。   
    
   FD_ZERO    清空這個集合;   
   FD_SET 往這個集合裡面加入一個檔案控制代碼;   
   FD_ISSET      查看某一個檔案控制代碼是否被設定了;

   'fd_set') 是一組檔案描述符(fd)的集合。由於fd_set類型的長度在不同平台上不同,因此應該用一組標準的宏定義來處理此類變數:  

   fd_set set;      

   FD_ZERO(&set);        /* 將set清零 */    

   FD_SET(fd, &set);     /* 將fd加入set */   

   FD_CLR(fd, &set);     /* 將fd從set中清除 */    

   FD_ISSET(fd, &set);   /* 判斷fd是否處於可用狀態 是為true */  

2使用介紹:

<font face="Verdana">fd_set rdfds; /* 先申明一個 fd_set 集合來儲存我們要檢測的 socket控制代碼 */<br />struct timeval tv; /* 申明一個時間變數來儲存時間 */<br />int ret; /* 儲存傳回值 */<br />FD_ZERO(&rdfds); /* 用select函數之前先把集合清零 */<br />FD_SET(socket, &rdfds); /* 把要檢測的控制代碼socket加入到集合裡 */<br />tv.tv_sec = 1;<br />tv.tv_usec = 500; /* 設定select等待的最大時間為1秒加500毫秒 */<br />ret = select(socket + 1, &rdfds, NULL, NULL, &tv); /* 檢測我們上面設定到集合rdfds裡的控制代碼是否有可讀資訊 */<br />if(ret < 0) perror("select");/* 這說明select函數出錯 */<br />else if(ret == 0) printf("逾時/n"); /* 說明在我們設定的時間值1秒加500毫秒的時間內,socket的狀態沒有發生變化 */<br />else { /* 說明等待時間還未到1秒加500毫秒,socket的狀態發生了變化 */<br /> printf("ret=%d/n", ret); /* ret這個傳回值記錄了發生狀態變化的控制代碼的數目,由於我們只監視了socket這一個控制代碼,所以這裡一定ret=1,如果同時有多個控制代碼發生變化返回的就是控制代碼的總和了 */<br /> /* 這裡我們就應該從socket這個控制代碼裡讀取資料了,因為select函數已經告訴我們這個控制代碼裡有資料可讀 */<br /> if(FD_ISSET(socket, &rdfds)) { /* 先判斷一下socket這外被監視的控制代碼是否真的變成可讀的了 */<br /> /* 讀取socket控制代碼裡的資料 */<br /> recv(...);<br /> }<br />}<br /> </font>

注意select函數的第一個參數,是所有加入集合的控制代碼值的最大那個值還要加1。比如我們建立了3個控制代碼:

int sa, sb, sc;<br />sa = socket(...); /* 分別建立3個控制代碼並串連到伺服器上 */<br />connect(sa,...);<br />sb = socket(...);<br />connect(sb,...);<br />sc = socket(...);<br />connect(sc,...);<br />FD_SET(sa, &rdfds);/* 分別把3個控制代碼加入讀監視集合裡去 */<br />FD_SET(sb, &rdfds);<br />FD_SET(sc, &rdfds);</p><p>

在使用select函數之前,一定要找到3個控制代碼中的最大值是哪個,我們一般定義一個變數來儲存最大值,取得最大socket值如下:

int maxfd = 0;<br />if(sa > maxfd) maxfd = sa;<br />if(sb > maxfd) maxfd = sb;<br />if(sc > maxfd) maxfd = sc;<br />

然後調用select函數:

ret = select(maxfd + 1, &rdfds, NULL, NULL, &tv); /* 注意是最大值還要加1 */

 

3 關於 Select 的 FD_SETSIZE


 

nt select(int n, fd_set *rd_fds, fd_set *wr_fds, fd_set *ex_fds, struct timeval *timeout);
Select
用到了fd_set結構,從man
page裡可以知道fd_set能容納的控制代碼和FD_SETSIZE相關。實際上fd_set在*nix下是一個bit標誌數組,每個bit表示對應下標
的fd是不是在fd_set中。fd_set只能容納編號小於 FD_SETSIZE的那些控制代碼。
FD_SETSIZE預設是1024,如果向
fd_set裡放入過大的控制代碼,數組越界以後程式就會垮掉。系統預設限制了一個進程最大的控制代碼號不超過1024,但是可以通過ulimit
-n命令/setrlimit函數來擴大這一限制。如果不幸一個程式在FD_SETSIZE=1024的環境下編譯,運行時又遇到ulimit n
> 1024的,那就只有祈求上帝保佑不會垮掉了。

通過上述說明,可以看到如果串連很多的話,建議還是使用epoll來解決這個問題。

4 select 機制的優勢

為什麼會出現select模型?

先看一下下面的這句代碼:
int iResult = recv(s, buffer,1024);
這是用來接收資料的,在預設的阻塞模式下的通訊端裡,recv會阻塞在那裡,直到通訊端串連上有資料可讀,把資料讀到buffer裡後recv函數才會返
回,不然就會一直阻塞在那裡。在單線程的程式裡出現這種情況會導致主線程(單線程程式裡只有一個預設的主線程)被阻塞,這樣整個程式被鎖死在這裡,如果永
遠沒資料發送過來,那麼程式就會被永遠鎖死。這個問題可以用多線程解決,但是在有多個通訊端串連的情況下,這不是一個好的選擇,擴充性很差。
再看代碼:
int iResult = ioctlsocket(s, FIOBIO, (unsigned long *)&ul);
iResult = recv(s, buffer,1024);

這一次recv的調用不管通訊端串連上有沒有資料可以接收都會馬上返回。原因就在於我們用ioctlsocket把通訊端設定為非阻塞模式了。不過
你跟蹤
一下就會發現,在沒有資料的情況下,recv確實是馬上返回了,但是也返回了一個錯誤:WSAEWOULDBLOCK,意思就是請求的操作沒有成功完成。
看到這裡很多人可能會說,那麼就重複調用recv並檢查傳回值,直到成功為止,但是這樣做效率很成問題,開銷太大。

select模型的出現就是為瞭解決上述問題。

select模型的關鍵是使用一種有序的方式,對多個通訊端進行統一管理與調度

看核心代碼:(這裡只給出服務端的)

while ( 1 )
{
// 初始化fdset
FD_ZERO( &fdsRead );

// 將server通訊端添加到可讀集合中
FD_SET( sockServer, &fdsRead );

// 調用select
select( 0, &fdsRead, NULL, NULL, &tv );

// 判斷server通訊端的狀態,如果通訊端還在可讀集合中,
// 說明有資料可以讀入,則建立通訊端可以成功
if ( FD_ISSET( sockServer, &fdsRead ) )
{
sockAccept = accept( sockServer, (sockaddr*)&addr, &nLen );
// 有資料可讀,進行相關處理
}

 

 

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.