send/sendto和recv/recvfrom各自的區別
一般情況下:
send(),recv()用於TCP,sendto()及recvfrom()用於UDP
但是send(),recv()也可以用於UDP,sendto()及recvfrom()也可以用於TCP
sendto可以在引數中指定傳送的目標地址 , send需要socket已建立連線, sendto 可用於無連線的 socket 對於send的有連線socket,兩者一樣,sendto最後兩個引數沒用.
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)
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。
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服務。但在傳送或接收資料報時,核心會自動為之加上目地和源地址資訊。
Asynchronous:表示只是提供一個callback function,issue 網絡動作後,不需要專門的thread進行等待,網絡事件發生後,kernel會自動調用callback function (including signal-driven I/O, Asynchronous I/O,Overlapped with Completion Routine)。
connect函式
- sd:sd是socket的描述符,即是前個Example的sockfd
- serverAddr:負責提供關於這個socket的所有信息
- addr_len:它的意義簡單明瞭,就是*serverAddr的大小
SO_REUSEADDR有什麼用處和怎麼使用?
- 當有一個有相同本地地址和端口的socket1處於TIME_WAIT狀態時,而你啟動的程序的socket2要佔用該地址和端口,你的程序就要用到該選項。
- SO_REUSEADDR允許同一port上啟動同一服務器的多個實例(多個進程)。但每個實例綁定的IP地址是不能相同的。在有多塊網卡或用IP Alias技術的機器可以測試這種情況。
- SO_REUSEADDR允許單個進程綁定相同的端口到多個socket上,但每個socket綁定的ip地址不同。這和2很相似,區別請看UNPv1。
- SO_REUSEADDR允許完全相同的地址和端口的重複綁定。但這只用於UDP的多播,不用於TCP。
沒有留言:
張貼留言