从tcp,udp链接角度看send和sendto的区别

send函数适用于TCP连接,sendto函数适用于UDP连接。send在连接状态下使用,sendto在UDP或连接模式套接字中,dest_addr和addrlen参数可能被忽略。虽然sendto可用于TCP,但通常不推荐。recv和recvfrom的使用方式类似。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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);

### TCP UDP 数据传输函数解析 #### TCP 协议中的 `send` `recv` 在TCP协议中,用于发送接收数据的主要函数分别是`send``recv`。 对于`send`函数而言,在向连接套接字写入数据时会调用此方法。其定义如下: ```c int send(SOCKET s, const char* buf, int len, int flags); ``` - 参数`s`表示已建立连接的套接口描述符; - `buf`指向要发送的数据缓冲区首地址; - `len`指定待发送数据长度; - `flags`通常设置为0,保留特殊用途[^2]; 而`recv`则负责读取来自对方发来的消息: ```c int recv(SOCKET s, char* buf, int len, int flags); ``` - 同样地,`s`代表目标套接口句柄; - `buf`用来存储收到的信息; - `len`表明最大可接受的消息大小; - `flags`一般设为零; #### UDP 协议下的 `sendto` 及 `recvfrom` 不同于TCP的是,由于UDP属于无连接型服务模型,因此需要额外提供目的端信息来完成一次完整的通信过程。这也就意味着当通过UDP方式传递数据包时,除了常规参数外还需附加远程主机的相关属性作为输入项之一。 具体来说就是利用`sendto`来进行数据分组投递操作: ```c int sendto( SOCKET s, const char *buf, int len, int flags, struct sockaddr *to, int tolen ); ``` 其中新增加的部分有: - `to`: 描述远端节点位置的对象实例(即IP地址与端口号组合),类型应为`sockaddr_in`; - `tolen`: 上述结构体变量所占空间尺寸[^1]; 至于接收方面,则借助于`recvfrom`实现: ```c int recvfrom( SOCKET s, char *buf, int len, int flags, struct sockaddr *from, int *fromlen ); ``` 这里同样引入了一个新的成员——`from`以及对应的`fromlen`, 它们的作用是用来记录当前正在处理的那个客户端的身份特征.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值