对于 UDP 套接字,发送函数不会失败,但写入的数据仍然比请求的少吗?

Posted

技术标签:

【中文标题】对于 UDP 套接字,发送函数不会失败,但写入的数据仍然比请求的少吗?【英文标题】:Can it realistically happen that for an UDP socket, the send function doesn't fail, but still writes less data than requested? 【发布时间】:2017-09-30 10:58:30 【问题描述】:

来自man 2 sendto

成功时,这些调用会返回发送的字节数。出错时,返回 -1,并正确设置 errno。

我是否理解写入所有数据失败不被视为这些函数的失败,因此在写入 UDP 套接字时,send() 函数写入的数据少于请求的数据实际上可能会发生,但是原因errno中未指定此故障的原因?

或者我可以假设send() 将返回-1 并适当地设置errno,或者返回请求发送的字节数?

换句话说:这个错误处理代码是否足够:

if(send(udp_sock_fd, buf, buflen, 0) == -1) 
  int err = errno;
  fprintf(stderr, "Send failed:\n");
  fprintf(stderr, strerror(err));

还是有必要这样写:

ssize_t bytes_send = send(udp_sock_fd, buf, buflen, 0);
if(bytes_send == -1) 
  int err = errno;
  fprintf(stderr, "Send failed:\n");
  fprintf(stderr, strerror(err));
 else if(bytes_send < buflen) 
  fprintf(stderr, "Incomplete send for unknown reason.\n");

【问题讨论】:

好问题,我也很好奇。请打任何告诉你“试试看”的人。 试试吧。 :) @jnbbender slap ;P 更严肃的一点是,我不确定这有什么帮助,我想我不会引发这种情况,并且再多的失败尝试也无法证明这种情况不会发生。 如果数据报协议在应用程序级别被拆分,那么它就没有意义了! 【参考方案1】:

显然,@Paul Bentley 已经提供了正确的答案,但如果您担心——即使这不应该发生——可能会出现一些罕见的错误情况,它可能会有所帮助请注意,至少对于特定的实现(Linux),net/ipv4/udp.c 中的udp_sendmsg 的代码(这是 UDP 套接字上 send 的最终调用)只有一个可以返回非负数的出口值,并返回调用者提供的长度:

int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)

        ... code that doesn't modify len ...
out:
        ...
        if (!err)
               return len;
        ...

【讨论】:

【参考方案2】:

没有只发送数据报的一部分的概念。要么全部进行,要么都不进行。操作系统或网络驱动程序不会为您拆分数据报。返回发送的字符数必须是出于礼貌,以便与其他 send API 函数保持一致。

也来自手册页:

对于sendto(),如果消息太长,无法通过底层协议原子传递,则返回错误EMSGSIZE,消息不传输。

【讨论】:

以上是关于对于 UDP 套接字,发送函数不会失败,但写入的数据仍然比请求的少吗?的主要内容,如果未能解决你的问题,请参考以下文章

在 Go 中写入客户端 UDP 套接字

UDP sendto 永远不会失败

Linux学习_UDP编程

Linux socket使用多线程发送

Java将udp数据包发送到dns服务器

基于UDP的服务器端/客户端