從tcp,udp鏈接角度看send和sendto的區別

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, 
				const struct sockaddr *dest_addr, socklen_t addrlen);

send函數一般用於TCP鏈接,sendto函數一般用於UDP連接。

來看看man手冊裏怎麼說send與sendto:

The send() call may be used only when the socket is in a connected state (so that the
intended recipient is known).
The only difference between send() and write(2) is the presence of flags. With a zero
flags argument, send() is equivalent to write(2). Also, the following
callsend(sockfd, buf, len, flags);is equivalent tosendto(sockfd, buf, len, flags, NULL, 0);

If sendto() is used on a connection-mode (SOCK_STREAM, SOCK_SEQPACKET) socket, the arguments dest_addr and addrlen are ignored (and the error EISCONN may be returned when they are not NULL and 0), and the error ENOTCONN is returned when the socket was not actually connected. Otherwise, the address of the target is given by dest_addr with addrlen specifying its size.

解釋:
send()調用只能在套接字處於連接狀態時使用(以便知道對端)。send()和write(2)唯一的的區別在於標誌位flag。當flag==0時,send()等價於write(2)寫。send()也等價於sendto(sockfd,buf,len,flags,NULL,0);

如果sendto()用於連接模式(SOCK_STREAM, SOCK_SEQPACKET)套接字,則dest_addr和addrlen參數被忽略(當它們不是NULL和0時,可能返回錯誤EISCONN),當socket沒有建立連接(即udp場景時),目標的地址由dest_addr給出,addrlen指定其地址大小。

所以說其實sendto()也是可以用於tcp通信的,只是我們一般不這麼做。


下面對參數爲什麼被忽略做一個解釋:

send函數只有一個能聯想到客戶端地址的參數,就是第一個參數sockfd。當客戶端與服務端鏈接建立成功後,在服務器端每一個客戶都有一個專用的socket,毫無疑問就可以把它看作這個客戶端的地址映射。

sendto能聯想到客戶端地址的參數有兩個:sockfd 和 dest_addr,但在實際應用中對所有UDP客戶sockfd參數都使用同一個值,所以可以推斷這個socket是爲所有UDP客戶使用的,不能看做目的客戶端的地址映射,只有dest_addr纔是目的客戶端的地址映射(ip地址和端口號)。

recv()和recvfrom同理,我只將接口列在下面,大家再琢磨琢磨,很容易就能弄明白。

 ssize_t recv(int sockfd, void *buf, size_t len, int flags);

       ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
		                 struct sockaddr *src_addr, socklen_t *addrlen);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章