日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

recv/send堵塞和非堵塞

發布時間:2023/12/8 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 recv/send堵塞和非堵塞 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

recv/send堵塞和非堵塞理解

  • TCP之深入淺出send和recv
    • 需要理解的3個概念
    • 實例詳解send()
  • send函數
  • recv函數

參考:
TCP之深入淺出send和recv
linux下非阻塞的tcp研究

題外話

今天在看epoll的ET模式時,說ET模式時,套接字描述符必須設置成非堵塞模式,為什么 IO 多路復用要搭配非阻塞 IO?
于是想看看堵塞和非堵塞recv/send的區別,網上魚龍混雜的博文,錯誤百出,查了好久,在此做個總結,如有錯誤的地方,希望大家指出來。

關于阻塞和非阻塞read/write,可以參考阻塞和非阻塞read/write
-------------------------------------這部分轉載于TCP之深入淺出send和recv

TCP之深入淺出send和recv

需要理解的3個概念

1.TCP socket的buffer
每個TCP socket在內核中都有一個發送緩沖區和一個接收緩沖區,TCP的全雙工的工作模式以及TCP的流量(擁塞)控制便是依賴于這兩個獨立的buffer以及buffer的填充狀態。

接收緩沖區把數據緩存入內核,應用進程一直沒有調用recv()進行讀取的話,此數據會一直緩存在相應socket的接收緩沖區內。

再啰嗦一點,不管進程是否調用recv()讀取socket,對端發來的數據都會經由內核接收并且緩存到socket的內核接收緩沖區之中

recv()所做的工作,就是把內核緩沖區中的數據拷貝到應用層用戶的buffer里面,并返回,僅此而已。進程調用send()發送的數據的時候,最簡單情況(也是一般情況),將數據拷貝進入socket的內核發送緩沖區之中,然后send便會在上層返回。換句話說,send()返回之時,數據不一定會發送到對端去(和write寫文件有點類似),send()僅僅是把應用層buffer的數據拷貝進socket的內核發送buffer中,發送是TCP的事情,和send其實沒有太大關系。接收緩沖區被TCP用來緩存網絡上來的數據,一直保存到應用進程讀走為止。

對于TCP,如果應用進程一直沒有讀取,接收緩沖區滿了之后,發生的動作是:收端通知發端,接收窗口關閉(win=0)。這個便是滑動窗口的實現。保證TCP套接口接收緩沖區不會溢出,從而保證了TCP是可靠傳輸。因為對方不允許發出超過所通告窗口大小的數據。 這就是TCP的流量控制,如果對方無視窗口大小而發出了超過窗口大小的數據,則接收方TCP將丟棄它。

查看測試機的socket發送緩沖區大小,

cat /proc/sys/net/ipv4/tcp_wmem 4096 16384 4194304

第一個值是一個限制值,socket發送緩存區的最少字節數;
第二個值是默認值;
第三個值是一個限制值,socket發送緩存區的最大字節數;
根據實際測試,發送緩沖區的尺寸在默認情況下的全局設置是16384字節,即16k。
在測試系統上,發送緩存默認值是16k。
proc文件系統下的值和sysctl中的值都是全局值,應用程序可根據需要在程序中使用setsockopt()對某個socket的發送緩沖區尺寸進行單獨修改,詳見文章《TCP選項之SO_RCVBUF和SO_SNDBUF》,不過這都是題外話。

2.接收窗口(滑動窗口)
TCP連接建立之時的收端的初始接受窗口大小是14600,細節如圖2所示(129是收端,130是發端)

圖2
接收窗口是TCP中的滑動窗口,TCP的收端用這個接受窗口----win=14600,通知發端,我目前的接收能力是14600字節。
后續發送過程中,收端會不斷的用ACK ( ACK的全部作用請參照博文《TCP之ACK發送情景 )。通知發端自己的接收窗口的大小狀態,如圖3,而發端發送數據的量,就根據這個接收窗口的大小來確定,發端不會發送超過收端接收能力的數據量。這樣就起到了一個流量控制的的作用。

圖3

圖3說明
21,22兩個包都是收端發給發端的ACK包

第21個包,收端確認收到的前7240個字節數據,7241的意思是期望收到的包從7241號開始,序號加了1.同時,接收窗口從最初的14656(如圖2)經過慢啟動階段增加到了現在的29120。用來表明現在收端可以接收29120個字節的數據,而發端看到這個窗口通告,在沒有收到新的ACK的時候,發端可以向收端發送29120字節這么多數據。

第22個包,收端確認收到的前8688個字節數據,并通告自己的接收窗口繼續增長為32000這么大。

3.單個TCP的負載量和MSS的關系
MSS在以太網上通常大小是1460字節,而我們在后續發送過程中的單個TCP包的最大數據承載量是1448字節,這二者的關系可以參考博文《TCP之1460MSS和1448負載》。

實例詳解send()

實例功能說明:接收端129作為客戶端去連接發送端130,連接上之后并不調用recv()接收,而是sleep(1000),把進程暫停下來,不讓進程接收數據。內核會緩存數據至接收緩沖區。發送端作為服務器接收TCP請求之后,立即用ret = send(sock,buf,70k,0);這個C語句,向接收端發送70k數據。
我們現在來觀察這個過程。看看究竟發生了些什么事。wireshark抓包截圖如下圖4

圖4說明,包序號等同于時序

  • 客戶端sleep在recv()之前,目的是為了把數據壓入接收緩沖區。服務端調用"ret = send(sock,buf,70k,0);"這個C語句,向接收端發送70k數據。由于發送緩沖區大小16k,send()無法將70k數據全部拷貝進發送緩沖區,故先拷貝16k進入發送緩沖區,下層發送緩沖區中有數據要發送,內核開始發送。上層send()在應用層處于阻塞狀態;
  • 11號TCP包,發端從這兒開始向收端發送1448個字節的數據;
  • 12號TCP包,發端沒有收到之前發送的1448個數據的ACK包,仍然繼續向收端發送1448個字節的數據;
  • 13號TCP包,收端向發端發送1448字節的確認包,表明收端成功接收總共1448個字節。此時收端并未調用recv()讀取,目前發送緩沖區中被壓入1448字節。由于處于慢啟動狀態,win接收窗口持續增大,表明接受能力在增加,吞吐量持續上升;
  • 14號TCP包,收端向發端發送2896字節的確認包,表明收端成功接收總共2896個字節。此時收端并未調用recv()讀取,目前發送緩沖區中被壓入2896字節。由于處于慢啟動狀態,win接收窗口持續增大,表明接受能力在增加,吞吐量持續上升;
  • 15號TCP包,發端繼續向收端發送1448個字節的數據;
  • 16號TCP包,收端向發端發送4344字節的確認包,表明收端成功接收總共4344個字節。此時收端并未調用recv()讀取,目前發送緩沖區中被壓入4344字節。由于處于慢啟動狀態,win接收窗口持續增大,表明接受能力在增加,吞吐量持續上升;
  • 從這兒開始,我略去很多包,過程類似上面過程。同時,由于不斷的發送出去的數據被收端用ACK確認,發送緩沖區的空間被逐漸騰出空地,send()內部不斷的把應用層buf中的數據向發送緩沖區拷貝,從而不斷的發送,過程重復。70k數據并沒有被完全送入內核,send()不管是否發送出去,send不管發送出去的是否被確認,send()只關心buf中的數據有沒有被全部送往發送緩沖區。如果buf中的數據沒有被全部送往發送緩沖區,send()在應用層阻塞,負責等待發送緩沖區中有空余空間的時候,逐步拷貝buf中的數據;如果buf中的數據被全部拷入發送緩沖區,send()立即返回。
  • 經過慢啟動階段接收窗口增大到穩定階段,TCP吞吐量升高到穩定階段,收端一直處于sleep狀態,沒有調用recv()把內核中接收緩沖區中的數據拷貝到應用層去,此時收端的接收緩沖區中被壓入大量數據;
  • 66號、67號TCP數據包,發端繼續向收端發送數據;
  • 68號TCP數據包,收端發送ACK包確認接收到的數據,ACK=62265表明收端已經收到62264字節的數據,這些數據目前被壓在收端的接收緩沖區中。win=3456,比較之前的16號TCP包的win=23296,表明收端的窗口已經處于收縮狀態,收端的接收緩沖區中的數據遲遲未被應用層讀走,導致接收緩沖區空間吃緊,故收縮窗口,控制發送端的發送量,進行流量控制;
  • 69號、70號TCP數據包,發端在接收窗口允許的數據量的范圍內,繼續向收端發送2段1448字節長度的數據;
  • 71號TCP數據包,至此,收端已經成功接收65160字節的數據,全部被壓在接收緩沖區之中,接收窗口繼續收縮,尺寸為1600字節;
  • 72號TCP數據包,發端在接收窗口允許的數據量的范圍內,繼續向收端發送1448字節長度的數據;
  • 73號TCP數據包,至此,收端已經成功接收66608字節的數據,全部被壓在接收緩沖區之中,接收窗口繼續收縮,尺寸為192字節。
  • 74號TCP數據包,和我們這個例子沒有關系,是別的應用發送的包;
  • 75號TCP數據包,發端在接收窗口允許的數據量的范圍內,向收端發送192字節長度的數據;
  • 76號TCP數據包,至此,收端已經成功接收66800字節的數據,全部被壓在接收緩沖區之中,win=0接收窗口關閉,接收緩沖區滿,無法再接收任何數據;
  • 77號、78號、79號TCP數據包,由keepalive觸發的數據包,響應的ACK持有接收窗口的狀態win=0,另外,ACK=66801表明接收端的接收緩沖區中積壓了66800字節的數據。
  • 從以上過程,我們應該熟悉了滑動窗口通告字段win所說明的問題,以及ACK確認數據等等。現在可得出一個結論,接收端的接收緩存尺寸應該是66800字節(此結論并非本篇主題)。
    send()要發送的數據是70k,現在發出去了66800字節,發送緩存中還有16k,應用層剩余要拷貝進內核的數據量是N=70k-66800-16k。接收端仍處于sleep狀態,無法recv()數據,這將導致接收緩沖區一直處于積壓滿的狀態,窗口會一直通告0(win=0)。發送端在這樣的狀態下徹底無法發送數據了,send()的剩余數據無法繼續拷貝進內核的發送緩沖區,最終導致send()被阻塞在應用層;
  • send()一直阻塞中。。。
  • 圖4和send()的關系說明完畢。

    那什么時候send返回呢?有3種返回場景

    send()返回場景

    • 場景1,我們繼續圖4這個例子,不過這兒開始我們就跳出圖4所示的過程了
  • 接收端sleep(1000)到時間了,進程被喚醒,代碼片段如圖5

    圖5
  • 隨著進程不斷的用"recv(fd,buf,2048,0);"將數據從內核的接收緩沖區拷貝至應用層的buf,在使用win=0關閉接收窗口之后,現在接收緩沖區又逐漸恢復了緩存的能力,這個條件下,收端會主動發送攜帶"win=n(n>0)"這樣的ACK包去通告發送端接收窗口已打開;

  • 發端收到攜帶"win=n(n>0)"這樣的ACK包之后,開始繼續在窗口運行的數據量范圍內發送數據。發送緩沖區的數據被發出;
  • 收端繼續接收數據,并用ACK確認這些數據;
  • 發端收到ACK,可以清理出一些發送緩沖區空間,應用層send()的剩余數據又可以被不斷的拷貝進內核的發送緩沖區;
  • 不斷重復以上發送過程;
  • send()的70k數據全部進入內核,send()成功返回。
    • 場景2,我們繼續圖4這個例子,不過這兒開始我們就跳出圖4所示的過程了
  • 收端進程或者socket出現問題,給發端發送一個RST;
  • 內核收到RST,send返回-1。
    • 場景3,和以上例子沒關系
      連接上之后,馬上send(1k),這樣,發送的數據肯定可以一次拷貝進入發送緩沖區,send()拷貝完數據立即成功返回。

    send()發送結論

    send()只是負責拷貝,拷貝完立即返回,不會等待發送和發送之后的ACK。如果socket出現問題,RST包被反饋回來。在RST包返回之時,如果send()還沒有把數據全部放入內核或者發送出去,那么send()返回-1,errno被置錯誤值;如果RST包返回之時,send()已經返回,那么RST導致的錯誤會在下一次send()或者recv()調用的時候被立即返回。

    概念上容易疑惑的地方

  • TCP協議本身是為了保證可靠傳輸,并不等于應用程序用tcp發送數據就一定是可靠的,必須要容錯;
  • send()和recv()沒有固定的對應關系,不定數目的send()可以觸發不定數目的recv(),這話不專業,但是還是必須說一下,初學者容易疑惑;
  • 關鍵點,send()只負責拷貝,拷貝到內核就返回,我通篇在說拷貝完返回,很多文章中說send()在成功發送數據后返回,成功發送是說發出去的東西被ACK確認過send()只拷貝,不會等ACK
  • 此次send()調用所觸發的程序錯誤,可能會在本次返回,也可能在下次調用網絡IO函數的時候被返回。
  • 實際上理解了阻塞式的,就能理解非阻塞的。

    參考linux下非阻塞的tcp研究

    在阻塞模式下,send函數的過程是將應用程序請求發送的數據拷貝到內核發送緩存中,待發送數據完全被拷貝到內核發送緩存區中才返回,當然如果內核發送緩存區一直沒有空間能容納待發送的數據,則一直阻塞;

    在非阻塞模式下,send函數的過程也是將應用程序請求發送的數據拷貝內核發送緩存中,區別在于非堵塞模式下,send函數不需要等到待發送數據完全被拷貝到內核發送區中才返回。
    如果內核緩存區可用空間不夠容納所有待發送數據,則盡能力的拷貝,返回成功拷貝的大小;
    如果緩存區可用空間為0,則返回-1,同時設置errno為EAGAIN.

    -------------------------------------------------以下部分為個人思考總結所得

    send函數

    參考linux下非阻塞的tcp研究

    注意并不是send把s的發送緩沖中的數據傳到連接的另一端的,而是底層TCP/IP協議棧傳的,send僅僅是把用戶buf中的數據copy到s的發送緩沖區的剩余空間里

    在阻塞模式下,send函數的過程是將應用程序請求發送的數據拷貝到內核發送緩存中,待發送數據完全被拷貝到內核發送緩存區中才返回,當然如果內核發送緩存區一直沒有空間能容納待發送的數據,則一直阻塞;

    在非阻塞模式下,send函數的過程也是將應用程序請求發送的數據拷貝內核發送緩存中,區別在于非堵塞模式下,send函數不需要等到待發送數據完全被拷貝到內核發送區中才返回。
    如果內核緩存區可用空間不夠容納所有待發送數據,則盡能力的拷貝,返回成功拷貝的大小;
    如果緩存區可用空間為0,則返回-1,同時設置errno為EAGAIN.

    看看官方手冊中的描述https://linux.die.net/man/2/send,摘抄如下

    If the message is too long to pass atomically through the underlying protocol, the error EMSGSIZE is returned, and the message is not transmitted.

    No indication of failure to deliver is implicit in a send(). Locally detected errors are indicated by a >return value of -1.

    When the message does not fit into the send buffer of the socket, send() normally blocks, unless the socket has been placed in nonblocking I/O mode. In nonblocking mode it would fail with the error EAGAIN or EWOULDBLOCK in this case. The select(2) call may be used to determine when it is possible to send more data.

    在看看《UNIX網絡編程卷1》第 16 章 非阻塞式 I/O中的描述,如下

    int send( SOCKET s, const char FAR *buf, int len, int flags );

    該函數的:
    第一個參數指定發送端套接字描述符;
    第二個參數指明一個存放應用程序要發送數據的緩沖區;
    第三個參數指明實際要發送的數據的字節數;
    第四個參數一般置0。

    堵塞模式下socket的send函數的執行流程:
    1.如果內核發送緩沖區可用大小為0,send()直接堵塞。。。,直到內核發送緩沖區里的數據被系統發送后,騰出空間后,send()再將剩余的待發送數據拷貝到內核發送緩沖區中去;

    2.如果內核發送緩沖區可用空間小于待發送的數據長度len,則send()函數會先把部分數據拷貝到內核發送緩沖區中,然后會阻塞。。。,直到內核發送緩沖區里的數據被系統發送后,騰出空間后,send()再將剩余的待發送數據拷貝到內核發送緩沖區中去;

    不知道為啥百度百科上send()是 “send先比較待發送數據的長度len和套接字s的發送緩沖的長度, 如果len大于s的發送緩沖區的長度,該函數返回SOCKET_ERROR;”
    明顯感覺描述不對,按這樣說,那不就無法發送大于socket內核發送緩沖區的長度的數據了,可以看看socket內核發送緩沖區的默認大小
    cat /proc/sys/net/ipv4/tcp_wmem
    4096 16384 4161536
    表明socket內核發送緩沖區默認大小為16kB,那發送大于16kB的數據怎么辦呢?所以這里明顯有問題
    官方手冊的原話是
    If the message is too long to pass atomically through the underlying protocol, the error EMSGSIZE is returned, and the message is not transmitted.

    可以看看TCP之深入淺出send和recv中的抓包實驗,可知待發送數據大于socket的內核緩沖區大小時,也是可以發送的,沒有返回SOCKET_ERROR。
    也可以看看這里socket之send與發送緩沖區大小的關系

    可知,待發送數據的長度大于s的內核發送緩沖區的長度時,會先將s(發送端)的內核發送緩沖區填滿,然后發送端會將內核發送緩沖區的數據發送到接收端socket的內核接收緩沖區,所以s(發送端)的內核發送緩沖區又會慢慢騰出空間,send又會將待發送數據往s(發送端)的內核發送緩沖區中copy,

    極端情況就是s(發送端)的內核發送緩沖區填滿,接收端socket的內核接收緩沖區也被填滿,但是send待發送的數據還是沒發完,此時會堵塞。。。,等待s(發送端)的內核發送緩沖區產生空閑內存,

    3.如果內核發送緩沖區可用空間大于待發送的數據長度len,send()函數直接將待發送數據完全拷貝到內核的發送緩沖區,然后成功返回。

    要注意send()函數把待發送數據完全拷貝到s的內核發送緩沖區中之后,它就返回了,但是此時這些數據并不一定馬上被傳到連接的另一端。

    注意:在Unix系統下,如果send在等待協議傳送數據時網絡斷開的話,調用send的進程會接收到一個SIGPIPE信號,進程對該信號的默認處理是進程終止。

    Send函數的返回值有三類:
    (1)返回值=0:
    (2)返回值<0:發送失敗,錯誤原因存于全局變量errno中
    (3)返回值>0:表示發送的字節數(實際上是拷貝到發送緩沖中的字節數)

    錯誤代碼:
    EBADF 參數s 非合法的socket處理代碼。
    EFAULT 參數中有一指針指向無法存取的內存空間
    ENOTSOCK 參數s為一文件描述詞,非socket。
    EINTR 被信號所中斷。
    EAGAIN 此操作會令進程阻斷,但參數s的socket為不可阻斷。
    ENOBUFS 系統的緩沖內存不足
    ENOMEM 核心內存不足
    EINVAL 傳給系統調用的參數不正確。

    recv函數

    recv函數把內核接收緩沖中的數據copy到buf

    int recv( SOCKET s,char FAR *buf,int len, int flags);

    具體的看看https://linux.die.net/man/2/recv
    有一段話摘錄在此

    If no messages are available at the socket, the receive calls wait for a message to arrive, unless the socket is nonblocking (see fcntl(2)), in which case the value -1 is returned and the external variable errno is set to EAGAIN or EWOULDBLOCK.
    如果內核接收緩沖區內沒有數據可讀,則recv會堵塞,直到有數據到達,然后返回;
    如果內核接收緩沖區內沒有數據可讀,但是recv設置為非堵塞,那么recv會返回-1,同時將errno置為EAGAIN or EWOULDBLOCK.
    The receive calls normally return any data available, up to the requested amount, rather than waiting for receipt of the full amount requested.
    recv返回值為讀取到的字節數(這個數是內核接收緩沖區中可讀取的字節數,可能是1個字節或者某個字節),最大可為buf區的大小len。recv并不是要等到讀取完len個字節才返回。

    posix 系統上,
    在阻塞模式下
    如果內核緩沖區沒有數據可讀, recv ()會阻塞,直到有一些數據存在可以讀取為止。然后,它將返回讀取到的數據(可能少于請求的數量len) ,返回的數最大為len。

    在非阻塞模式下
    如果內核緩沖區沒有數據可讀,recv 將立即返回 -1,設置 errno 為 EAGAIN 或 ewoudblock。
    所以,通常在循環中調用 recv,直到得到所需的量,同時檢查返回碼是0(另一端斷開)還是 -1(一些錯誤)。

    在看看《UNIX網絡編程卷1》第 16 章 非阻塞式 I/O中的描述,如下

    int recv( SOCKET s,char FAR *buf,int len, int flags);

    該函數的:
    第一個參數指定接收端套接字描述符;
    第二個參數指明一個緩沖區,該緩沖區用來存放recv函數接收到的數據;
    第三個參數指明buf的長度;
    第四個參數一般置0。

    堵塞socket的recv函數的執行流程:
    來自https://baike.baidu.com/item/recv%28%29

    下面的描述正確性還不確定,反正網上都是這么說的,暫且看看吧

    當應用程序調用recv函數時,recv先等待s的發送緩沖 中的數據被協議傳送完畢,如果協議在傳送s的發送緩沖中的數據時出現網絡錯誤,那么recv函數返回SOCKET_ERROR,

    如果s的發送緩沖中沒有數 據或者數據被協議成功發送完畢后,**recv先檢查套接字s的接收緩沖區,如果s接收緩沖區中沒有數據或者協議正在接收數據,那么recv就一直等待,直到協議把數據接收完畢。 **

    個人質疑:直到協議把數據接收完畢是什么意思?TCP是數據流,那什么叫做完畢呢?
    假如,接收端套接字的接收緩沖區為16kB大小,發送端套接字一次發送8kB數據過來,肯定需要一點時間后,這8KB的數據才能完全到達接收端套接字的接收緩沖區,那接收端recv是一看到接收緩沖區有一點數據就返回?還是等接收緩沖區有8KB數據之后才返回?那如果發送端套接字發送完8kB數據后,立馬又發送8kB數據呢?
    所以接收端套接字的recv根本不知道發送端什么時候才把數據發送完畢,因為發送端可以想發多少發多少
    看看《UNIX網絡編程卷1》第 16 章 非阻塞式 I/O中的描述中的原話

    可以知道正確的描述應該是:調用recv時,若該套接字的內核接收緩沖區沒有數據可讀,recv會堵塞(注意,這里前提是在堵塞模式下),直到有一些數據到達,這一些數據可能是單個字節,也可能是一個完整的TCP分節中的數據,recv就會被喚醒,然后返回copy到的字節數。

    注意協議接收到的數據可能大于buf的長度,所以 在這種情況下要調用幾次recv函數才能把s的接收緩沖中的數據copy完。recv函數僅僅是copy數據,真正的接收數據是協議來完成的

    recv函數返回其實際copy的字節數。如果recv在copy時出錯,那么它返回SOCKET_ERROR;如果recv函數在等待協議接收數據時網絡中斷了,那么它返回0。

    注意:在Unix系統下,如果recv函數在等待協議接收數據時網絡斷開了,那么調用recv的進程會接收到一個SIGPIPE信號,進程對該信號的默認處理是進程終止。

    • 默認情況下socket是阻塞的。
      阻塞與非阻塞recv返回值沒有區別,都是:
      <0 出錯
      =0 對方調用了close API來關閉連接
      > 0 接收到的數據大小,

    特別地:返回值<0時并且(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)的情況下認為連接是正常的,繼續接收。

    只是阻塞模式下recv會一直阻塞直到接收到數據,非阻塞模式下如果沒有數據就會返回,不會阻塞著讀,因此需要循環讀取)。

    返回說明:
    (1)成功執行時,返回接收到的字節數。
    (2)若另一端已關閉連接則返回0,這種關閉是對方主動且正常的關閉
    (3)失敗返回-1,errno被設為以下的某個值

    EAGAIN:套接字已標記為非阻塞,而接收操作被阻塞或者接收超時
    EBADF:sock不是有效的描述詞
    ECONNREFUSE:遠程主機阻絕網絡連接
    EFAULT:內存空間訪問出錯
    EINTR:操作被信號中斷
    EINVAL:參數無效
    ENOMEM:內存不足
    ENOTCONN:與面向連接關聯的套接字尚未被連接上
    ENOTSOCK:sock索引的不是套接字

    總結

    以上是生活随笔為你收集整理的recv/send堵塞和非堵塞的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。