標籤:style blog color 使用 os strong 資料 div
send、recv和sendto、recvfrom,一般情況下,send、recv在TCP協議下使用,sendto、recvfrom在UDP協議下使用,也可以在TCP協議下使用,不過用的很少。
1、send
這裡只描述同步socket的send函數的執行流程。
s:通訊端 | buf:儲存發送資料 | len:發送資料長度
當調用該函數時,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訊號,進程對該訊號的預設處理是進程終止。
2、recv
這裡只描述同步Socket的recv函數的執行流程。
s:通訊端 | buf:儲存發送資料 | len:發送資料長度
當應用程式調用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訊號,進程對該訊號的預設處理是進程終止。
3、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()的情況與sendto()類似,也需要目的地址,函數原型為:
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服務。但在發送或接收資料報時,核心會自動為之加上目地和源地址資訊。