socket的recv和send帶來的疑惑

2021-06-10 12:56:02 字數 1985 閱讀 7001

昨天在測試socket的傳輸時,發現有時候recv會會返回接收位元組的長度為0,

開始沒有在意,但是過了一會系統重啟了。這樣一來帶來的麻煩就大了。

因為發現每次系統重啟時,都在send函式附近,為了驗證在send時系統重啟,於是在send函式前後各加了乙個列印輸出,發現每次都是在第乙個列印有輸出,第二個沒有。

於是猜測是send時,阻塞導致給看門狗餵狗的執行緒沒有切換執行,造成了系統復位重啟。

(這裡沒有考慮記憶體溢位的錯誤,是因為設定了sigsegv訊號的處理函式。 如果傳送記憶體訪問錯誤,會捕捉到,並列印出提示資訊,但是這裡的復位重啟並沒有列印資訊)

每次出現這樣的問題前,recv總會返回接受位元組為0。因為使用了select,如果沒有資料到來是不會接收的,但是為什麼接收了,而且收到的位元組長度還是0。所以考慮怎麼recv會返回0,而且又為什麼send的傳送導致系統的看門狗竟然長時間無法餵狗。

在apue上recv返回值為0的描述:

如果傳送者已經呼叫shutdown來結束傳輸,或者網路協議支援預設的順序關閉並且傳送端已經關閉,那麼當所有的資料接收完畢後,recv返回0.

後來man recv 返回值為0的描述:

these  calls  return  the  number  of bytes received, or -1 if an error occurred.  the return value will be 0 when the peer  has  performed  an

orderly shutdown.

顯然,當recv返回值為零的時候,對方已經呼叫shutdown了,關閉連線。

由此,當recv返回值為0時,如果想繼續雙向連線,就需要重新建立連線了。一般很少用到shutdown,實現所謂的半關閉(半關閉,tcp提供了連線的一端在結束它的傳送後還能收來自另一端資料的能力)。

recv返回值為零的問題,是弄明白了,但是為什麼send會阻塞,導致看門狗復位呢?

因為send只是把資料拷貝到核心,

apue上的描述:

當send成功返回時,並不必然表示連線的另一端的程序接收資料。所保證的僅是當send成功是,資料已經無誤地傳送到網路上了。

man  send:

when  the  message  does  not  fit  into the send buffer of the socket,

send() normally blocks, unless the socket has been placed in non-block-

ing  i/o  mode.   in  non-blocking  mode it would return eagain in this

case.  the select(2) call may be used to determine when it is  possible

to send more data.

如果send在這裡阻塞,就應該表明現在資料沒有拷貝到核心,沒有成功的傳送到網路上,所以在這裡阻塞等待。這樣導致看門狗復位的原因應該就是由於傳送緩衝區已滿,則send就要阻塞,直到資料資料可以傳送,以至於執行緒沒有切換,造成沒有餵狗。可思議是有功select先判斷是否可寫,然後再呼叫send函式,進行傳送。

依然沒有解決的幾個問題:

為什麼send阻塞了,看門狗餵狗執行緒就沒有切換執行呢?執行緒的切換不應該是這樣的。

因為send阻塞時,會導致當前執行緒掛起,那麼對於核心來說切換到其他執行緒是很簡單的。還有可能的就是,傳送時傳入的資料長度有問題,那麼就需要把它列印出來看看了。

如果recv返回值是0,那麼也就是說是shutdown的緣故,那麼對於send函式應該不會有影響,因為對方雖然關閉了乙個連線但是還有乙個連線可以用來接收還是可以的。send函式傳送時出現阻塞,應該是send buffer被佔滿了,那麼因為每次傳送的資料都不大,只有不到一百個位元組,不應該是一次傳送導致send buffer出問題。比較合理的是,傳送了多次但是沒有傳送成功(傳送到網路上),導致資料累積在send buffer中,但是為什麼會沒有傳送成功(傳送到網路上)呢?

SOCKET之Send和Recv理解

int send socket s,const char buf,int len,int flags 引數描述 同步 socket 的send函式的執行流程如下 如果len大於傳送緩衝區剩餘空間大小 不足放入剩餘傳送緩衝區 send就一直 等待協議把s傳送緩衝區中的資料傳送完 如果len小於傳送緩衝...

socket為send和recv設定超時時間

linux和windows下用setsockopt設定so sndtimeo,so rcvtimeo的引數的一點區別 udp的socket在某些情況 如對方關閉時,本地可能sendto不出去資料,然後recvfrom就會被阻塞,這時就需要設定 這兩個引數的值提高程式質量。linux struct t...

socket中send函式和recv函式的理解

int send socket s,const char buf,int len,int flags 引數描述 同步 socket 的send函式的執行流程如下 如果len大於傳送緩衝區剩餘空間大小 不足放入剩餘傳送緩衝區 send就一直 等待協議把s傳送緩衝區中的資料傳送完 如果len小於傳送緩衝...