从一个未知长度的UDP套接字中读取数据

huangapple go评论87阅读模式
英文:

Read data from a UDP socket with an unknown length

问题

如何在不事先知道长度的情况下使用socket.ReadFromUDP方法?目前我有以下代码:

buff := make([]byte, <unknownLength>)
for {
    socket.ReadFromUDP(buff)
    fmt.Println("读取的字节数:", buff.Len())
}

我尝试过以下代码,但它总是读取1024个字节:

buff := make([]byte, 1024)
for {
    bytesRead, _, _ := socket.ReadFromUDP(buff)
    fmt.Println("读取的字节数:", bytesRead)
}

我从服务器接收的数据包大小从几个字节到几百个字节不等。

英文:

How could I socket.ReadFromUDP without knowing the length beforehand? Right now I have something like this.

buff := make([]byte, &lt;unknownLength&gt;)
for {
    socket.ReadFromUDP(buff)
    fmt.Println(&quot;Bytes read:&quot;, buff.Len())
}

I tried this, but it always read 1024 bytes.

buff := make([]byte, 1024)
for {
    bytesRead, _, _ := socket.ReadFromUDP(buff)
    fmt.Println(&quot;Bytes read:&quot;, bytesRead)
}

The packets I'm receiving from the server vary from a couple of bytes to hundres of bytes.

答案1

得分: 12

一个UDP套接字以离散的数据报形式接收消息(因此被称为SOCK_DGRAM)。尽管Go语言具有相对清晰的网络API,但你仍然需要了解一些底层套接字的知识(https://stackoverflow.com/questions/2862071/how-large-should-my-recv-buffer-be-when-calling-recv-in-the-socket-library)。

UDP套接字将读取到接收缓冲区的大小,并丢弃其余部分,因此无法像在TCP流中那样继续读取。在UDP套接字上的单次接收会消耗网络中的一个数据报。

尽管UDP数据包的理论最大有效负载为65,507字节,但由于路径MTU限制,实际上你可能不会收到超过1400字节的消息。如果将缓冲区设置得比这个大得多,比如4096字节,那么你将非常安全,但你也可以使用64k的缓冲区来确保。

尽管在Go语言中无法确定待处理数据包的大小,但你可以通过以下方式判断是否丢失了数据:

oob := make([]byte, 1024)
n, on, flags, addr, err := c.ReadMsgUDP(buff, oob)
if flags &amp; syscall.MSG_TRUNC != 0 {
    fmt.Println("truncated read")
}
英文:

A UDP socket receives messages in discrete datagrams (hence the name SOCK_DGRAM). Though Go has a relatively clean networking API, you still can't get away without knowing a little bit about the underlying sockets (https://stackoverflow.com/questions/2862071/how-large-should-my-recv-buffer-be-when-calling-recv-in-the-socket-library).

A UDP socket will Read up to the size of the receiving buffer and will discard the rest, so you can't continue to read like you would on a TCP stream. A single receive on a UDP socket consumes a single datagram from the network.

Though the theoretical max payload of a UDP packet is 65,507, in practice you are probably not going to get messages over 1400 bytes because of path MTU limits. If you set your buffer considerably larger than this, to something like 4096 bytes you will be very safe, but you could use a 64k buffer to be certain.

Though it's not feasible in Go to try and determine the pending packet size, you can tell if you lost data for what it's worth:

oob := make([]byte, 1024)
n, on, flags, addr, err := c.ReadMsgUDP(buff, oob)
if flags &amp; syscall.MSG_TRUNC != 0 {
    fmt.Println(&quot;truncated read&quot;)
}

答案2

得分: 4

基本技术是使用一个比预期的最大数据报大一个单位的缓冲区。如果你收到一个这样大小的数据报,你就知道它不适合你的应用协议,应该将其丢弃,可能在记录下来以防它是发送方的编程错误,或者你的应用协议没有完全指定。

英文:

The basic technique is to use a buffer one larger than the largest expected datagram. Then if you get a datagram that size you know it doesn't fit your application protocol and should be discarded, probably after logging it in case it's a programming error at the sender, or your application protocol is incompletely specified.

huangapple
  • 本文由 发表于 2014年7月12日 02:59:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/24704680.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定