缓冲式套接字读取

3

我是一名有用的助手,可以为您进行翻译。以下是需要翻译的内容:

我有一个问题 - 我不知道发送到我的UDP服务器的数据量。

当前代码如下 - 在irb中测试:

require 'sockets'
sock = UDPSocket.new
sock.bind('0.0.0.0',41588)

sock.read # Returns nothing
sock.recvfrom(1024) # Requires length of data to be read - I don't know this

我可以将recvfrom设置为65535或其他较大的数字,但这似乎是一种不必要的hack。

recvfrom和recvfrom_nonblock在指定长度后都会丢弃任何内容。

我是否错误地设置了套接字?


如果您正在编写客户端,为什么不创建一个协议,其中前两个字节是一个短整型,告诉您要读取的数据长度? - NG.
我假设你正在处理某种协议,那么这个协议对最大数据报大小有什么要说的吗? - Len Holgate
那看起来是解决这个问题的方法。我很惊讶这些信息还没有被公开 - 网络堆栈肯定已经知道数据包的长度了吧? - tgandrews
2个回答

4
请注意,UDP是一种数据包协议,不像TCP那样是流式的。每次从UDP套接字读取时,会出列一个完整的数据包。您可以将这些标志传递给recvfrom(2)
MSG_PEEK
此标志会导致接收操作从接收队列的开头返回数据, 而无需将该数据从队列中删除。因此,后续的接收调用将返回相同的数据。
MSG_WAITALL
此标志请求操作阻塞,直到满足完整请求。但是, 如果捕获到信号、发生错误或断开连接,或接收到下一个与返回值不同类型的数据,则调用仍可能返回比请求的数据少。
MSG_TRUNC
返回数据包的实际长度,即使它比传递的缓冲区长。仅适用于数据报套接字。

如果您真的不知道可能会收到多大的数据包(协议限制为65507字节,请参见此处),并且不关心调用系统调用的数量加倍,那么可以先使用MSG_PEEK,然后从套接字中读取确切数量的字节。

或者您可以设置一个近似的最大缓冲区大小,比如4096,然后使用MSG_TRUNC检查是否丢失了任何数据。

还要注意,UDP数据报很少大于1472 - 以太网数据大小为1500减去20字节的IPv4头减去8字节的UDP头 - 没有人喜欢分段。

编辑:

Socket :: MSG_PEEK 在那里,对于其他内容,您可以使用整数值:

MSG_TRUNC   0x20
MSG_WAITALL 0x100

请查看您的系统头文件(在Linux上为/usr/include/bits/socket.h)以确保。


谢谢您的回复,但我不明白如何在Ruby中实现您的建议。您描述的常量似乎并不可用。我受到库所提供内容的限制。如果能提供示例将不胜感激。 - tgandrews

3

查看Ruby的recvfrom()文档,参数是一个最大长度。只需提供65535(UDP数据报的最大长度);返回的数据应该是发送的数据报,无论其大小如何,您都应该能够像在Ruby中处理任何类似字符串的东西一样确定其大小。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接