2

当发送(或写入)缓冲区将满时,让我说,只有 500 字节的空间。如果我有一个非阻塞 fd,然后做

  n = send(fd, buf, 1000,0)

在这里我会得到 n<0,我会得到 EWOULDBLOCK 或 EAGAIN 错误。我的问题是:

1 这里,将send500 字节写入发送缓冲区还是将 0 字节写入发送缓冲区?

2 如果 500 字节被发送到缓冲区并且如果 fd 是 UDP 套接字,那么数据报被分成 2 部分?

3 我需要使用fd发送许多数据报,如果这次发送缓冲区已满(如果有 EWOULDBLOCK 或 EAGAIN 错误),我需要制作一个待处理的数据报列表(一个 FIFO 队列)。每次我想发送一些数据报时,我都必须检查待处理列表以查看它是否为空。如果不为空,则先发送待处理列表中的数据报。在我看来,这种设计有点麻烦。并且该设计类似于通过用户空间挂起列表扩展内核(顺便说一句,它在内核中吗?)发送缓冲区。有没有更好的解决方案?

谢谢!

4

2 回答 2

3

以下仅适用于 UDP(并且仅在 linux 中,尽管其他类似),但这似乎是您要问的。

在 UDP 套接字上设置非阻塞模式是完全无关的(对于发送),因为发送永远不会阻塞——它立即发送数据包,没有任何缓冲。

可能(如果机器很忙)存在缓冲区空间问题(用于数据包处理的瞬时数据包缓冲区用完),但在这种情况下,无论 fd 是阻塞还是非阻塞,调用都将返回 ENOBUFS阻塞。这应该是非常罕见的。

如果您生成数据包的速度比网络接收它们的速度快(在快速机器和 10Mbit 以太网端口上很容易做到),那么内核将开始丢弃传出的数据包。不幸的是,没有简单的方法来检测何时发生这种情况(您可以检查接口是否有 TX 丢弃的数据包,但这不会告诉您哪些数据包被丢弃)。

如果您使用 UDP_CORK 套接字选项也可能会出现问题,该选项缓冲写入套接字的数据而不是发送数据包,并且在未设置 CORK 选项时仅发送单个数据包。在这种情况下,如果缓冲区变得太大,您将获得 EMSGSIZE(同样,NONBLOCKING 设置无关紧要)。

于 2013-05-20T18:44:08.140 回答
1

如果您在谈论 UDP,那么您在这里完全偏离主题 - 对于 UDP,SO_SNDBUF套接字选项的值限制了您可以发送的数据报的大小。换句话说,没有真正的每个套接字发送缓冲区(尽管数据仍在内核中排队等待由适当的网络控制器发送出去)。EMSGSIZE如果你一次尝试更多,你会得到send(2)

EWOULDBLOCK但是对于 TCP,只有在发送缓冲区完全没有空间时,您才会得到,即没有数据从用户复制到内核。否则sent(2)的返回值会准确告诉您已复制了多少字节。

于 2013-05-20T18:02:58.227 回答