Tru64上的sendto正在返回ENOBUF

时间:2010-05-11 10:46:42

标签: linux unix sockets

我目前在Tru64上运行一个旧系统,它使用sendto()函数涉及许多UDP套接字。套接字在我们的代码中用于向/从各种进程发送消息,然后最终发送到远程连接的胖客户端应用程序。有时,胖客户端的套接字会卡住,这可能导致其中一些消息被建立起来。我的问题是如何确定当前的缓冲区大小,以及如何确定最大的消息缓冲区。下面的代码给出了我如何设置端口并使用sendto函数的片段。

/* need to adjust the maximum size we can send on this */
/* as it needs to be able to cope with the biggest     */
/* messages we send                                    */

lenlen = sizeof(len) ;

/* allow double for when the system is under load */
int                 lenlen, len ;
lenlen = sizeof(len) ;
len = 2 * 32000;

msg_socket = socket( AF_UNIX,SOCK_DGRAM, 0);

 result = setsockopt(msg_socket, SOL_SOCKET, SO_SNDBUF, (char *)&len, lenlen) ;

    result = sendto( msg_socket,
                         (char *)message,
                         (int)message_len,
                         flags,
                         dest_addr,
                         addrlen);

请注意。我们已将此应用程序移植到Linux,但问题似乎并未出现在那里。

非常感谢任何帮助。

此致

2 个答案:

答案 0 :(得分:2)

UDP发送缓冲区大小与TCP不同 - 它只是限制了数据报的大小。引用史蒂文斯UNP卷。 1:

... UDP套接字具有发送缓冲区大小(我们可以使用SO_SNDBUF套接字选项更改,第7.5节),但这只是可以写入套接字的最大UDP数据报的上限。如果应用程序写入的数据报大于套接字发送缓冲区大小,则返回EMSGSIZE。由于UDP不可靠,因此不需要保留应用程序数据的副本,也不需要实际的发送缓冲区。 (应用程序数据通常会在传递到协议堆栈时复制到某种形式的内核缓冲区中,但在传输数据后,数据链路层会丢弃此副本。)
UDP简单地预先设置8字节标头并将数据报传递给IP。 IPv4或IPv6预先设置其标头,通过执行路由功能确定输出接口,然后将数据报添加到数据链路输出队列(如果它适合MTU)或者将数据报分段并将每个片段添加到数据链路输出队列。如果UDO应用程序发送大数据报(比如说2,000字节的数据报),则碎片的可能性要高于TCP。因为TCP将应用程序数据分解为MSS大小的块,这在UDP中没有对应物。
write成功返回到UDP套接字告诉我们数据报或数据报的所有片段都已添加到数据链路输出队列。如果队列中没有数据报或其中一个片段的空间,ENOBUFS通常会返回给应用程序。
不幸的是,某些实现没有返回此错误,使应用程序没有指示数据报被丢弃甚至没有被传输。

最后一个脚注需要注意 - 但看起来Tru64在manual page中列出了此错误代码。

执行此操作的正确方法是将未完成的消息排入应用程序本身,并在每次系统调用后仔细检查返回值和errno。这仍然不能保证传送(因为UDP接收器可能会丢弃数据包而不通知发送者)。在两侧/所有侧检查带有netstat -s的UDP数据包丢弃计数器,看它们是否在增长。除了切换到TCP或实现自己的超时/确认和重新传输逻辑之外,实际上没有办法解决这个问题。

答案 1 :(得分:0)

您可能应该使用某种拥塞控制来避免网络过载。到目前为止,最简单的方法是使用TCP而不是UDP。

它在Linux上失败的次数较少,因为UDP套接字等待Linux上本地网络接口队列中的空间(除非您将它们设置为非阻塞)。但是,对于任何操作系统,如果过满队列不在本地系统中,则数据包将被静默删除。