2010-05-11 31 views
2

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

/* 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上,并且这个问题似乎并没有出现在那里。

任何帮助将不胜感激。

Regards

回答

0

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

由于UDP套接字在Linux上的本地网络接口队列中等待空间(除非您将它们设置为非阻塞),所以在Linux上发生故障的频率较低。但是,对于任何操作系统,如果溢出队列不在本地系统中,则数据包将被无声丢弃。

2

UDP发送缓冲区大小与TCP不同 - 它只是限制数据报的大小。引用Stevens UNP Vol。 1:

... UDP套接字具有发送缓冲区大小(我们可以用 SO_SNDBUF套接字选项,第7.5节改变),但是这仅仅是对最大尺寸的UDP数据报可以是上限写入套接字。如果应用程序写入大于套接字发送缓冲区大小的数据报,则返回 EMSGSIZE。由于UDP不可靠,因此不需要保留应用程序数据的副本,也不需要实际的发送缓冲区。 (因为它向下通过协议栈,但数据被发送之后该副本由数据链路层丢弃该应用程序数据被正常地复制到某种形式的内核缓冲区。)
        UDP简单地预先考虑8-字节头并将数据报传递给IP。 IPv4或IPv6预先通过其头部,通过执行路由功能来确定输出接口,然后将数据报添加到数据链路输出队列(如果它适合于MTU内)或对数据报进行分段并将每个分段添加到数据链路输出队列。如果一个UDO应用程序发送较大的数据报(比如说2000字节的数据报),则存在比使用TCP更高的碎片概率。因为TCP将应用程序数据分解为MSS大小的块,这在UDP中没有对应的东西。
       从 write UDP套接字的成功返回告诉我们,无论是数据包或数据报的所有碎片都被添加到数据链路输出队列。如果数据报或其片段之一没有空间,则 ENOBUFS通常返回给应用程序。
        不幸的是,有些实现不返回该错误,给应用程序没有迹象表明该数据报,甚至没有传输丢弃。

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

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