tcp socket阻塞與非阻塞

2021-07-10 23:44:03 字數 4165 閱讀 9514

1.sock預設為阻塞模式,下面的**可對sock設定為非阻塞模式

int flags = fcntl(sock, f_getfl, 0);

fcntl(sock, f_setfl, flags | o_nonblock);

假設當前**為伺服器,並且已經執行過如下**,

當sock為阻塞模式,呼叫accept會阻塞直到乙個請求到來

當sock為非阻塞模式,accept會返回-1,errno設定為eagain或者ewouldblock

static int ns_open_listening_socket_tcp()

else if (sock != -1)

return sock;

}

3,對於sock_stream 套接字,應用程式意識不到報文邊界,因為套接字提供的是位元組流服務,因此當從套接字讀出資料時,它也許不會返回所有由傳送程序所寫的位元組,最終獲取所有資料,也許要通過若干次函式呼叫得到

sock為阻塞和非阻塞對recv是沒有影響的,

recv在accept沒有建立新的sock之前,都是立即返回-1,並且errno 為 9,

#define ebadf 9 /* bad file number */

在accept建立好連線以後,沒有資料接收之前都會一直阻塞,

若有資料接收,recv則返回值》0;

若無資料接收,recv阻塞;

若對方斷開連線,則recv返回值為0;

那麼有錯誤處理函式:

當recv返回0時,套接字關閉,出錯close退出

當recv返回負數,並且不為以下幾種情況時,出錯退出:

#define eintr 4 /* interrupted system call */

#define einprogress 115 /* operation now in progress */

#define eagain 11 /* try again */

#define ewouldblock eagain /* operation would block */

static int ns_is_error(int n)

recv函式

int recv( socket s, char far *buf, int len, int flags);

不論是客戶還是伺服器應用程式都用recv函式從tcp連線的另一端接收資料。

該函式的第乙個引數指定接收端套接字描述符; 

第二個引數指明乙個緩衝區,該緩衝區用來存放recv函式接收到的資料; 

第三個引數指明buf的長度; 第四個引數一般置0。

這裡只描述同步socket的recv函式的執行流程。當應用程式呼叫recv函式時,

(1)recv先等待s的傳送緩衝中的資料被協議傳送完畢,如果協議在傳送s的傳送緩衝中的資料時出現網路錯誤,那麼recv函式返回socket_error,

(2)如果s的傳送緩衝中沒有資料或者資料被協議成功傳送完畢後,recv先檢查套接字s的接收緩衝區,

如果s接收緩衝區中沒有資料或者協議正在接收數 據,那麼recv就一直等待,直到協議把資料接收完畢。

當協議把資料接收完畢,recv函式就把s的接收緩衝中的資料copy到buf中

(注意協議接收到的資料可能大於buf的長度,所以 在這種情況下要呼叫幾次recv函式才能把s的接收緩衝中的資料copy完。

recv函式僅僅是copy資料,真正的接收資料是協議來完成的), recv函式返回其實際copy的位元組數。

如果recv在copy時出錯,那麼它返回socket_error;

如果recv函式在等待協議接收資料時網路中斷了,那麼它返回0。

預設 socket 是阻塞的 解阻塞與非阻塞recv返回值沒有區分,都是<0 出錯 =0 連線關閉 >0 接收到資料大小

特別:返回值<0時並且(errno == eintr || errno == ewouldblock || errno == eagain)的情況下認為連線是正常的,繼續接收。

只是阻塞模式下recv會阻塞著接收資料,非阻塞模式下如果沒有資料會返回,不會阻塞著讀,因此需要迴圈讀取)。

返回說明: 

成功執行時,返回接收到的位元組數。

另一端已關閉則返回0。

失敗返回-1,

errno被設為以下的某個值 

eagain:套接字已標記為非阻塞,而接收操作被阻塞或者接收超時 

ebadf:sock不是有效的描述詞 

econnrefuse:遠端主機阻絕網路連線 

efault:記憶體空間訪問出錯 

eintr:操作被訊號中斷 

einval:引數無效 

enomem:記憶體不足 

enotconn:與面向連線關聯的套接字尚未被連線上 

enotsock:sock索引的不是套接字 當返回值是0時,為正常關閉連線;

思考:當對側沒有send,即本側的套接字s的接收緩衝區無資料,返回值是什麼(eagain,原因為超時,待測)

測試**:

#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //offsetof

#include static int ns_is_error(int n)

static void ns_set_non_blocking_mode(int sock)

static int ns_open_listening_socket_tcp()

else if (sock != -1)

return sock;

}void main()

sleep(1);

} }

若要接收大檔案,則當客戶端斷開後,n為0 ,才會斷開連線,認為一次接收完畢。

若recv返回了,但沒有出錯,則不會關閉newsock,在下一輪中繼續接收

**如下:

void main()

; char out[10240];

int sock = ns_open_listening_socket_tcp();

newsock = -1;

while(1)

if(newsock>=0)

strcat(out,buf);

memset(buf,0,sizeof(buf));

} if(ns_is_error(n))

}}

若把accept以後的newsock設定為非阻塞,則為以下模式:設定newsock的超時時間,當recv超時後,返回,返回的n為-1,errno為11,這個時候,仍然不會認為出錯,等待下一次接收。
void main()

; char out[10240];

int sock = ns_open_listening_socket_tcp();

// int timeout=1;

struct timeval timeout = ;

newsock = -1;

while(1)

if(newsock>0)

printf("n:%d,errno:%d\n",n,errno);

if(ns_is_error(n))

} }

}

綜上,recv只有返回0時,才結束傳輸。

ns_is_error(n)為真 時,才關閉socket(真的結束了,即n==0,或者出錯了)

為假時,不用關閉socket下一輪繼續接收。

TCP Socket程式設計(非阻塞模式)(C )

伺服器 tcpserver.cpp 定義控制台應用程式的入口點。include stdafx.h include include pragma comment lib,ws2 32.lib define buf size 64 int tmain int argc,tchar argv 建立用於監聽...

阻塞與非阻塞賦值

李秋鳳,華清遠見嵌入式學院 講師。稍微接觸過verilog hdl的都對阻塞與非阻塞賦值略知一二,也是我們經常強調的重點之一,在課堂上還是有學員問什麼不一樣呢,為什麼我用阻塞賦值也能得出正確的結果呢?在編寫可綜合 的時候,建議大家不要忘了開啟rtl網表檢視器看看我們自己綜合出來的電路是不是自己想要的...

socket connect 阻塞與非阻塞

socket函式生成socket結構體時,預設生成的socket是阻塞的 如果我們使用connect去連線伺服器,而這時網路出現故障,則connect預設等候很長一段時間然後返回錯誤 我們可以設定socket為非阻塞模式,可以設定一定的等候時間,如果在設定的等候時間內connect失敗,則我們判定網...