Socket send函式和recv函式詳解

2021-08-13 09:51:44 字數 4202 閱讀 5131

出處:

1.send 函式 i

nt send( socket s, const char far *buf, int len, int flags ); 

不論是客戶還是伺服器應用程式都用send函式來向tcp連線的另一端傳送資料。

客戶程式一般用send函式向伺服器傳送請求,而伺服器則通常用send函式來向客戶程式傳送應答。

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

第二個引數指明乙個存放應用程式要傳送資料的緩衝區;

第三個引數指明實際要傳送的資料的位元組數;

第四個引數一般置0。 

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

(1)send先比較待傳送資料的長度len和套接字s的

傳送緩衝的長度

, 如果len大於s的傳送緩衝區的長度,該函式返回socket_error;

(2)如果len小於或者等於s的傳送緩衝區的長度,那麼send先檢查協議是否正在傳送s的傳送緩衝中的資料,如果是就等待協議把資料傳送完,如果協議還沒有開始傳送s的傳送緩衝中的資料或者s的傳送緩衝中沒有資料,那麼send就比較s的傳送緩衝區的剩餘空間和len

(3)如果len大於剩餘空間大小,send就一直等待協議把s的傳送緩衝中的資料傳送完

(4)如果len小於剩餘 空間大小,send就僅僅把buf中的資料copy到剩餘空間裡(

注意並不是send把s的傳送緩衝中的資料傳到連線的另一端的,而是協議傳的,send僅僅是把buf中的資料copy到s的傳送緩衝區的剩餘空間裡

)。如果send函式copy資料成功,就返回實際copy的位元組數,如果send在copy資料時出現錯誤,那麼send就返回socket_error;如果send在等待協議傳送資料時網路斷開的話,那麼send函式也返回socket_error。

要注意send函式把buf中的資料成功copy到s的傳送緩衝的剩餘空間裡後它就返回了,但是此時這些資料並不一定馬上被傳到連線的另一端

。如果協議在後續的傳送過程中出現網路錯誤的話,那麼下乙個socket函式就會返回socket_error。(每乙個除send外的socket函式在執 行的最開始總要先等待套接字的傳送緩衝中的資料被協議傳送完畢才能繼續,如果在等待時出現網路錯誤,那麼該socket函式就返回 socket_error)

注意:在unix系統下,如果send在等待協議傳送資料時網路斷開的話,呼叫send的程序會接收到乙個sigpipe訊號,程序對該訊號的預設處理是程序終止。

通過測試發現,非同步socket的send函式在網路剛剛斷開時還能傳送返回相應的位元組數,同時使用select檢測也是可寫的,但是過幾秒鐘之後,再send就會出錯了,返回-1。select也不能檢測出可寫了。

2. 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。

注意:在unix系統下,如果recv函式在等待協議接收資料時網路斷開了,那麼呼叫recv的程序會接收到乙個sigpipe訊號,程序對該訊號的預設處理是程序終止。

cp協議本身是可靠的,並不等於應用程式用tcp傳送資料就一定是可靠的.不管是否阻塞,send傳送的大小,並不代表對端recv到多少的資料.

在阻塞模式下, send函式的過程是將應用程式請求傳送的資料拷貝到傳送快取中傳送並得到確認後再返回.但由於傳送快取的存在,表現為:如果傳送快取大小比請求傳送的大小要大,那麼send函式立即返回,同時向網路中傳送資料;否則,send向網路傳送快取中不能容納的那部分資料,並等待對端確認後再返回(接收端只要將資料收到接收快取中,就會確認,並不一定要等待應用程式呼叫recv);

在非阻塞模式下,send函式的過程僅僅是將資料拷貝到協議棧的快取區而已,如果快取區可用空間不夠,則盡能力的拷貝,返回成功拷貝的大小;如快取區可用空間為0,則返回-1,同時設定errno為eagain.

-------------------例項分析----------------------

在實際應用中,如果傳送端是非阻塞傳送,由於網路的阻塞或者接收端處理過慢,通常出現的情況是,傳送應用程式看起來傳送了10k的資料,但是只傳送了2k到對端快取中,還有8k在本機快取中(未傳送或者未得到接收端的確認).那麼此時,接收應用程式能夠收到的資料為2k.假如接收應用程式呼叫recv函式獲取了1k的資料在處理,在這個瞬間,發生了以下情況之一,雙方表現為:

a. 傳送應用程式認為send完了10k資料,關閉了socket:

傳送主機作為tcp的主動關閉者,連線將處於fin_wait1的半關閉狀態(等待對方的ack),並且,傳送快取中的8k資料並不清除,依然會傳送給對端.如果接收應用程式依然在recv,那麼它會收到餘下的8k資料(這個前題是,接收端會在傳送端fin_wait1狀態超時前收到餘下的8k資料.), 然後得到乙個對端socket被關閉的訊息(recv返回0).這時,應該進行關閉.

b. 傳送應用程式再次呼叫send傳送8k的資料:

假 如傳送快取的空間為20k,那麼傳送快取可用空間為20-8=12k,大於請求傳送的8k,所以send函式將資料做拷貝後,並立即返回8192;

假如傳送快取的空間為12k,那麼此時傳送快取可用空間還有12-8=4k,send()會返回4096,應用程式發現返回的值小於請求傳送的大小值後,可以認為快取區已滿,這時必須阻塞(或通過select等待下一次socket可寫的訊號),如果應用程式不理會,立即再次呼叫send,那麼會得到-1的值, 在linux下表現為errno=eagain.

c. 接收應用程式在處理完1k資料後,關閉了socket:

接收主機作為主動關閉者,連線將處於fin_wait1的半關閉狀態(等待對方的ack).然後,傳送應用程式會收到socket可讀的訊號(通常是 select呼叫返回socket可讀),但在讀取時會發現recv函式返回0,這時應該呼叫close函式來關閉socket(傳送給對方ack);

如果傳送應用程式沒有處理這個可讀的訊號,而是在send,那麼這要分兩種情況來考慮,假如是在傳送端收到rst標誌之後呼叫send,send將返回 -1,同時errno設為econnreset表示對端網路已斷開,但是,也有說法是程序會收到sigpipe訊號,該訊號的預設響應動作是退出程序,如果忽略該訊號,那麼send是返回-1,errno為epipe(未證實);如果是在傳送端收到rst標誌之前,則send像往常一樣工作;

以上說的是非阻塞的send情況,假如send是阻塞呼叫,並且正好處於阻塞時(例如一次性傳送乙個巨大的buf,超出了傳送快取),對端socket關閉,那麼send將返回成功傳送的位元組數,如果再次呼叫send,那麼會同上一樣.

d. 交換機或路由器的網路斷開:

接收應用程式在處理完已收到的1k資料後,會繼續從快取區讀取餘下的1k資料,然後就表現為無資料可讀的現象,這種情況需要應用程式來處理超時.一般做法是設定乙個select等待的最大時間,如果超出這個時間依然沒有資料可讀,則認為socket已不可用.

傳送應用程式會不斷的將餘下的資料傳送到網路上,但始終得不到確認,所以快取區的可用空間持續為0,這種情況也需要應用程式來處理.

如果不由應用程式來處理這種情況超時的情況,也可以通過tcp協議本身來處理,具體可以檢視sysctl項中的:

net.ipv4.tcp_keepalive_intvl

net.ipv4.tcp_keepalive_probes

net.ipv4.tcp_keepalive_time 

Socket send函式和recv函式

不論是客戶還是伺服器應用程式都用send函式來向tcp連線的另一端傳送資料。客戶程式一般用send函式向伺服器傳送請求,而伺服器則通常用send函式來向客戶程式傳送應答。該函式的第乙個引數指定傳送端套接字描述符 第二個引數指明乙個存放應用程式要傳送資料的緩衝區 第三個引數指明實際要傳送的資料的位元組...

Socket send函式和recv函式

send 函式 int send socket s,const char far buf,int len,int flags 不論是客戶還是伺服器應用程式都用send函式來向tcp連線的另一端傳送資料。客戶程式一般用send函式向伺服器傳送請求,而伺服器則通常用send函式來向客戶程式傳送應答。該函...

Socket send函式和recv函式詳解zz

1.send 函式 i nt send socket s,const char far buf,int len,int flags 不論是客戶還是伺服器應用程式都用send函式來向tcp連線的另一端傳送資料。客戶程式一般用send函式向伺服器傳送請求,而伺服器則通常用send函式來向客戶程式傳送應答...