1. 程式人生 > >TCP通訊常用的send,sendto,recv,recvfrom函式詳解

TCP通訊常用的send,sendto,recv,recvfrom函式詳解

send函式

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

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

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

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

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

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

第四個引數一般置0。

這裡只描述同步Socket的send函式的執行流程。當呼叫該函式時,send先比較待發送資料的長度len和套接字s的傳送緩衝的 長度, 如果len大於s的傳送緩衝區的長度,該函式返回SOCKET_ERROR;如果len小於或者等於s的傳送緩衝區的長度,那麼send先檢查協議 是否正在傳送s的傳送緩衝中的資料,如果是就等待協議把資料傳送完,如果協議還沒有開始傳送s的傳送緩衝中的資料或者s的傳送緩衝中沒有資料,那麼 send就比較s的傳送緩衝區的剩餘空間和len,如果len大於剩餘空間大小send就一直等待協議把s的傳送緩衝中的資料傳送完,如果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訊號,程序對該訊號的預設處理是程序終止。

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

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

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

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

第三個引數指明buf的長度;

第四個引數一般置0。

這裡只描述同步Socket的recv函式的執行流程。當應用程式呼叫recv函式時,recv先等待s的傳送緩衝 中的資料被協議傳送完畢,如果協議在傳送s的傳送緩衝中的資料時出現網路錯誤,那麼recv函式返回SOCKET_ERROR,如果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訊號,程序對該訊號的預設處理是程序終止。

sendto和recvfrom一般用於UDP協議中,但是如果在TCP中connect函式呼叫後也可以用.

sendto()和recvfrom()——利用資料報方式進行資料傳輸  
  在無連線的資料報socket方式下,由於本地socket並沒有與遠端機器建立連線,所以在傳送資料時應指明目的地址,sendto()函式原型為:  
  int sendto(int sockfd, const void *msg,int len unsigned int flags, const struct sockaddr *to, int tolen);  
  該函式比send()函式多了兩個引數,to表示目地機的IP地址和埠號資訊,而tolen常常被賦值為sizeof (struct sockaddr)。Sendto 函式也返回實際傳送的資料位元組長度或在出現傳送錯誤時返回-1。  
  recvfrom()函式原型為:  
  int recvfrom(int sockfd,void *buf,int len,unsigned int lags,struct sockaddr *from,int *fromlen);  
  from是一個struct sockaddr型別的變數,該變數儲存源機的IP地址及埠號。fromlen常置為sizeof (struct sockaddr)。當recvfrom()返回時,fromlen包含實際存入from中的資料位元組數。Recvfrom()函式返回接收到的位元組數或當出現錯誤時返回-1,並置相應的errno。  
  應注意的一點是,當你對於資料報socket呼叫了connect()函式時,你也可以利用send()和recv()進行資料傳輸,但該socket仍然是資料報socket,並且利用傳輸層的UDP服務。但在傳送或接收資料報時,核心會自動為之加上目地和源地址資訊。