導航:首頁 > 編程系統 > linuxselect非阻塞

linuxselect非阻塞

發布時間:2021-10-26 05:56:26

linux 怎樣實現非阻塞connect

1. 設置socket
int oldOption = fcntl(sockfd, F_GETFL);
int newOption = oldOption | O_NONBLOCK;
//設置sockfd非阻塞
fcntl(sockfd, F_SETFL, newOption);12345

2. 執行connect
如果返回0,表示連接成功,這種情況一般在本機上連接時會出現(否則怎麼可能那麼快)
否則,查看error是否等於EINPROGRESS(表明正在進行連接中),如果不等於,則連接失敗
int ret = connect(sockfd, (struct sockaddr*)&addr, sizeof(addr));
if(ret == 0)
{
//連接成功
fcntl(sockfd, F_SETFL, oldOption);
return sockfd;
}
else if(errno != EINPROGRESS)
{
//連接沒有立即返回,此時errno若不是EINPROGRESS,表明錯誤
perror("connect error != EINPROGRESS");
return -1;
}12345678910111213141516

3. 使用select,如果沒用過select可以去看看
用select對socket的讀寫進行監聽
那麼監聽結果有四種可能
1. 可寫(當連接成功後,sockfd就會處於可寫狀態,此時表示連接成功)
2. 可讀可寫(在出錯後,sockfd會處於可讀可寫狀態,但有一種特殊情況見第三條)
3. 可讀可寫(我們可以想像,在我們connect執行完到select開始監聽的這段時間內,
如果連接已經成功,並且服務端發送了數據,那麼此時sockfd就是可讀可寫的,
因此我們需要對這種情況特殊判斷)
說白了,在可讀可寫時,我們需要甄別此時是否已經連接成功,我們採用這種方案:
再次執行connect,然後查看error是否等於EISCONN(表示已經連接到該套接字)。
4. 錯誤

if(FD_ISSET(sockfd, &writeFds))
{
//可讀可寫有兩種可能,一是連接錯誤,二是在連接後服務端已有數據傳來
if(FD_ISSET(sockfd, &readFds))
{
if(connect(sockfd, (struct sockaddr*)&addr, sizeof(addr)) != 0)
{
int error=0;
socklen_t length = sizeof(errno);
//調用getsockopt來獲取並清除sockfd上的錯誤.
if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &length) < 0)
{
printf("get socket option failed\n");
close(sockfd);
return -1;
}
if(error != EISCONN)
{
perror("connect error != EISCONN");
close(sockfd);
return -1;
}
}
}
//此時已排除所有錯誤可能,表明連接成功
fcntl(sockfd, F_SETFL, oldOption);
return sockfd;
}0

4. 恢復socket
因為我們只是需要將連接操作變為非阻塞,並不包括讀寫等,所以我們吃醋要將socket重新設置。
fcntl(sockfd, F_SETFL, oldOption);關於Linux命令的介紹,看看《linux就該這么學》,具體關於這一章地址3w(dot)linuxprobe/chapter-02(dot)html

❷ linux下設置recvfrom為非阻塞

可以使用
1 select pselect
2 poll

3可以使用fcntl給文件描述符添加O—UNBLOCK

❸ linux網路編程,為什麼要將文件描述符設置成非阻塞模式

非阻塞IO 和阻塞IO:

在網路編程中對於一個網路句柄會遇到阻塞IO 和非阻塞IO 的概念, 這里對於這兩種socket 先做一下說明:
基本概念:
阻塞IO::
socket 的阻塞模式意味著必須要做完IO 操作(包括錯誤)才會
返回。
非阻塞IO::
非阻塞模式下無論操作是否完成都會立刻返回,需要通過其他方
式來判斷具體操作是否成功。(對於connect,accpet操作,通過select判斷,
對於recv,recvfrom,send,sendto通過返回值+錯誤碼來判斷)

IO模式設置:
SOCKET
對於一個socket 是阻塞模式還是非阻塞模式的處理方法::
方法::
用fcntl 設置;用F_GETFL獲取flags,用F_SETFL設置flags|O_NONBLOCK;
同時,recv,send 時使用非阻塞的方式讀取和發送消息,即flags設置為MSG_DONTWAIT
實現
fcntl 函數可以將一個socket 句柄設置成非阻塞模式:
flags = fcntl(sockfd, F_GETFL, 0); //獲取文件的flags值。
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); //設置成非阻塞模式;
flags = fcntl(sockfd,F_GETFL,0);
fcntl(sockfd,F_SETFL,flags&~O_NONBLOCK); //設置成阻塞模式;
並在接收和發送數據時:
將recv, send 函數的最後有一個flag 參數設置成MSG_DONTWAIT
recv(sockfd, buff, buff_size,MSG_DONTWAIT); //非阻塞模式的消息發送
send(scokfd, buff, buff_size, MSG_DONTWAIT); //非阻塞模式的消息接受

普通文件
對於文件的阻塞模式還是非阻塞模式::
方法1、open時,使用O_NONBLOCK;
方法2、fcntl設置,使用F_SETFL,flags|O_NONBLOCK;

消息隊列
對於消息隊列消息的發送與接受::
//非阻塞 msgsnd(sockfd,msgbuf,msgsize(不包含類型大小),IPC_NOWAIT)
//阻塞 msgrcv(scokfd,msgbuf,msgsize(**),msgtype,IPC_NOWAIT);


阻塞與非阻塞讀的區別: //阻塞和非阻塞的區別在於沒有數據到達的時候是否立刻返回.
讀(read/recv/msgrcv):
讀的本質來說其實不能是讀,在實際中, 具體的接收數據不是由這些調用來進行,是由於系統底層自動完成的。read 也好,recv 也好只負責把數據從底層緩沖 到我們指定的位置.
對於讀來說(read, 或者recv) ::
阻塞情況下::
在阻塞條件下,read/recv/msgrcv的行為::
1、如果沒有發現數據在網路緩沖中會一直等待,
2、當發現有數據的時候會把數據讀到用戶指定的緩沖區,但是如果這個時候讀到的數據量比較少,比參數中指定的長度要小,read 並不會一直等待下去,而是立刻返回。
read 的原則::是數據在不超過指定的長度的時候有多少讀多少,沒有數據就會一直等待。
所以一般情況下::我們讀取數據都需要採用循環讀的方式讀取數據,因為一次read 完畢不能保證讀到我們需要長度的數據,
read 完一次需要判斷讀到的數據長度再決定是否還需要再次讀取。
非阻塞情況下::
在非阻塞的情況下,read 的行為::
1、如果發現沒有數據就直接返回,
2、如果發現有數據那麼也是採用有多少讀多少的進行處理.
所以::read 完一次需要判斷讀到的數據長度再決定是否還需要再次讀取。

對於讀而言:: 阻塞和非阻塞的區別在於沒有數據到達的時候是否立刻返回.
recv 中有一個MSG_WAITALL 的參數::
recv(sockfd, buff, buff_size, MSG_WAITALL),
在正常情況下recv 是會等待直到讀取到buff_size 長度的數據,但是這里的WAITALL 也只是盡量讀全,在有中斷的情況下recv 還是可能會被打斷,造成沒有讀完指定的buff_size的長度。
所以即使是採用recv + WAITALL 參數還是要考慮是否需要循環讀取的問題,在實驗中對於多數情況下recv (使用了MSG_WAITALL)還是可以讀完buff_size,
所以相應的性能會比直接read 進行循環讀要好一些。

注意:: //使用MSG_WAITALL時,sockfd必須處於阻塞模式下,否則不起作用。
//所以MSG_WAITALL不能和MSG_NONBLOCK同時使用。
要注意的是使用MSG_WAITALL的時候,sockfd 必須是處於阻塞模式下,否則WAITALL不能起作用。



阻塞與非阻塞寫的區別: //
寫(send/write/msgsnd)::
寫的本質也不是進行發送操作,而是把用戶態的數據 到系統底層去,然後再由系統進行發送操作,send,write返回成功,只表示數據已經 到底層緩沖,而不表示數據已經發出,更不能表示對方埠已經接收到數據.
對於write(或者send)而言,
阻塞情況下:: //阻塞情況下,write會將數據發送完。(不過可能被中斷)
在阻塞的情況下,是會一直等待,直到write 完,全部的數據再返回.這點行為上與讀操作有所不同。
原因::
讀,究其原因主要是讀數據的時候我們並不知道對端到底有沒有數據,數據是在什麼時候結束發送的,如果一直等待就可能會造成死循環,所以並沒有去進行這方面的處理;
寫,而對於write, 由於需要寫的長度是已知的,所以可以一直再寫,直到寫完.不過問題是write 是可能被打斷嗎,造成write 一次只write 一部分數據, 所以write 的過程還是需要考慮循環write, 只不過多數情況下一次write 調用就可能成功.

非阻塞寫的情況下:: //
非阻塞寫的情況下,是採用可以寫多少就寫多少的策略.與讀不一樣的地方在於,有多少讀多少是由網路發送的那一端是否有數據傳輸到為標准,但是對於可以寫多少是由本地的網路堵塞情況為標準的,在網路阻塞嚴重的時候,網路層沒有足夠的內存來進行寫操作,這時候就會出現寫不成功的情況,阻塞情況下會盡可能(有可能被中斷)等待到數據全部發送完畢, 對於非阻塞的情況就是一次寫多少算多少,沒有中斷的情況下也還是會出現write 到一部分的情況.

❹ 非阻塞select函數返回什麼csdn

阻塞方式block,就是進程或是線程執行到這些函數時必須等待某個事件的發生,如果事件沒有發生,進程或線程就被阻塞,函數不能立即返回。
使用Select就可以完成非阻塞non-block,就是進程或線程執行此函數時不必非要等待事件的發生,一旦執行肯定返回,以返回值的不同來反映函數的執行情況,如果事件發生則與阻塞方式相同,若事件沒有發生則返回一個代碼來告知事件未發生,而進程或線程繼續執行,所以效率較高。select能夠監視我們需要監視的文件描述符的變化情況。

❺ windows下的socket如果設置為非阻塞,那麼輪詢,太耗費資源。有沒有像linux下的,select或者說是epoll方法

可以用完成埠(等同於Linux下的epoll模型)來實現你的需求,以下是簡介:

Win32重疊I/O(Overlapped I/O)機制允許發起一個操作,然後在操作完成之後接受到信息。對於那種需要很長時間才能完成的操作來說,重疊IO機制尤其有用,因為發起重疊操作的線程 在重疊請求發出後就可以自由的做別的事情了。在WinNT和Win2000上,提供的真正的可擴展的I/O模型就是使用完成埠(Completion Port)的重疊I/O.完成埠---是一種WINDOWS內核對象。完成埠用於非同步方式的重疊I/0情況下,當然重疊I/O不一定非使用完成埠不 可,還有設備內核對象、事件對象、告警I/0等。但是完成埠內部提供了線程池的管理,可以避免反復創建線程的開銷,同時可以根據CPU的個數靈活的決定 線程個數,而且可以讓減少線程調度的次數從而提高性能其實類似於WSAAsyncSelect和select函數的機制更容易兼容Unix,但是難以實現 我們想要的「擴展性」。而且windows的完成埠機制在操作系統內部已經作了優化,提供了更高的效率。所以,我們選擇完成埠開始我們的伺服器程序的 開發。

❻ linux非阻塞socket中select的問題

select是不斷的監來聽文件描述自符,肯定能探測到它已經關閉了,那麼關閉的fd肯定就得從它的fd_set中退出來哇,退出來了,它自然就不監聽這個fd了,然後就只有等到超時退出了·····我個人的理解,說的好就給個分···呵呵··

❼ linux 使用epoll主要目的是啥 為了實現非阻塞么

socket本來就有阻塞和非阻塞兩種模式,與epoll無關。
epoll是針對多socket操作(從select升級內到poll再到epoll都是解決這個目容的)。
如果不用poll方法,在阻塞模式下,操作多socket,要麼用多線程,要麼用多進程,都會帶來一定的開發復雜度和性能降低。在非阻塞模式下,就要使用輪詢,浪費處理能力很厲害。

所以,epoll是為了讓程序只在一個線程中就能操作大量socket而提供的一個核心功能,同時還提供了很高的處理性能

❽ 非阻塞select和阻塞select的區別

可以用WINDOWS完成埠(等同於Linux下的epoll模型)來實現你的需求,以下是簡介:Win32重疊I/O(OverlappedI/O)機制允許發起一個操作,然後在操作完成之版後接受到信息。對於那種需要很長時間才能完成的操作來說,重疊IO機制尤其有用,因為發起重疊操作的線程在重疊請求發出後就可以自由的做別的事情了。在WinNT和Win2000上,提供的真正的可擴展的I/O模型就是使用完權成埠(CompletionPort)的重疊I/O.完成埠---是一種WINDOWS內核對象。完成埠用於非同步方式的重疊I/0情況下,當然重疊I/O不一定非使用完成埠不可,還有設備內核對象、事件對象、告警I/0等。但是完成埠內部提供了線程池的管理,可以避免反復創建線程的開銷,同時可以根據CPU的個數靈活的決定線程個數,而且可以讓減少線程調度的次數從而提高性能其實類似於WSAAsyncSelect和select函數的機制更容易兼容Unix,但是難以實現我們想要的「擴展性」。而且windows的完成埠機制在操作系統內部已經作了優化,提供了更高的效率。所以,我們選擇完成埠開始我們的伺服器程序的開發。

❾ linux 非阻塞connect errno什麼情況下不為einprogress

當connect在非阻塞模式下,會出現返回-1值,錯誤碼是EINPROGRESS,但如何判斷connect是聯通的呢?stevens書中說明要在connect後,繼續判斷該socket是否可寫?

若可寫,則證明鏈接成功。如何判斷可寫,有2種方案,一種是select判斷是否可寫,二用poll模型。

select:
int CheckConnect(int iSocket)
{
fd_set rset;

FD_ZERO(&rset);
FD_SET(iSocket, &rset);

timeval tm;
tm. tv_sec = 0;
tm.tv_usec = 0;

if ( select(iSocket + 1, NULL, &rset, NULL, &tval) <= 0)
{
close(iSocket);
return -1;
}

if (FD_ISSET(iSocket, &rset))
{
int err = -1;
socklen_t len = sizeof(int);
if ( getsockopt(iSocket, SOL_SOCKET, SO_ERROR ,&err, &len) < 0 )
{
close(iSocket);
printf("errno:%d %s\n", errno, strerror(errno));
return -2;
}

if (err)
{
errno = err;
close(iSocket);

return -3;
}
}

return 0;
}

poll:

int CheckConnect(int iSocket) {
struct pollfd fd;
int ret = 0;
socklen_t len = 0;

fd.fd = iSocket;
fd.events = POLLOUT;

while ( poll (&fd, 1, -1) == -1 ) {
if( errno != EINTR ){
perror("poll");
return -1;
}
}

len = sizeof(ret);
if ( getsockopt (iSocket, SOL_SOCKET, SO_ERROR, &ret, &len) == -1 ) {
perror("getsockopt");
return -1;
}

if(ret != 0) {
fprintf (stderr, "socket %d connect failed: %s\n",
iSocket, strerror (ret));
return -1;
}

return 0;
}

❿ 對於使用select的操作有沒有必要把IO設置為非阻塞

可以用WINDOWS完成埠(等同於Linux下的epoll模型)來實現你的需求,以下是簡介: Win32重疊I/O(Overlapped I/O)機制允許發起一個操作,然後在操作完成之後接受到信息。對於那種需要很長時間才能完成的操作來說,重疊IO機制尤其有用

閱讀全文

與linuxselect非阻塞相關的資料

熱點內容
好看的泰國男男電影 瀏覽:252
如何封網路 瀏覽:138
機戰坦克升級 瀏覽:614
韓國消失的眼角膜在哪能看 瀏覽:689
華為微雲下載的文件路徑手機 瀏覽:518
ps中選擇工具的快捷鍵 瀏覽:518
去電影院看電影坐腿上 瀏覽:624
隴南鄉村大數據公眾號 瀏覽:870
泰國《永恆》未刪減233 瀏覽:143
如何找到vivo手機收藏的文件 瀏覽:926
男男大尺度影片 瀏覽:75
有哪些網路平台可以免費找到律師 瀏覽:637
法國電影親密未減刪版 瀏覽:933
小米手機換機如何轉移數據文件夾 瀏覽:474
陽光網路技術有限公司 瀏覽:945
傻柱小說雨童在線閱讀 瀏覽:702
粗妹子的男多女少生活小說 瀏覽:754
扣扣怎麼發送文件夾 瀏覽:382
陳浩南出獄電影名 瀏覽:643

友情鏈接