【发布时间】:2018-04-21 19:10:14
【问题描述】:
我试图了解 bufio ReadBytes 在接收大数据包时的行为。我在 MTU=9001 的 unix 机器的 eth0 上运行一个简单的 Golang TCP 服务器。客户端是一台单独的机器(不直接连接到服务器)在 eth0 上运行一个 Python 客户端程序,MTU=1500。我的客户端 python 程序正在尝试发送一些大型数据包,这些数据包在客户端机器中按预期分片,并以最大 TCP MSS=1440 的 IP 数据包发送出去。到此为止,一切都很好。数据包到达服务器机器,我希望服务器机器在 OSI 第 4 层重新组装数据包。所以,据我了解,我的 Golang 套接字缓冲区应该得到 1 个大尺寸数据包(已经重新组装)。我的 Golang 服务器程序使用 bufio.ReadBytes('\x04') 读取消息中的 EOT 字符。我的客户端程序在每个数据包的有效负载末尾显式添加了一个 EOT 字符。
在服务器中,我看到接收到的数据包大小不一致。根据 ReadBytes() 的官方文档,它应该读取输入缓冲区中的所有数据,直到读入“delim”字符。我无法理解最大值。 bufio 包中用于读取器对象的缓冲区容量,希望任何人的帮助。
我的客户端程序 sn-p:
while True:
l = random.randint(1400, 10000)
data=("t"*l + '\x04').encode()
try:
if sock.send(data)==0:
print("Server closed connection")
else:
print("Data send done. Intended length=", l, " bytes")
except:
print ("Exception when sending data. Trace=" + traceback.format_exc())
time.sleep(10)
sock.close()
服务器程序sn-p:
reader := bufio.NewReader(conn)
readbuf := make([]byte, 1500)
err := io.EOF
for sockConnected {
conn.SetReadDeadline(time.Now().Add(10 * time.Millisecond))
readbuf, err = reader.ReadBytes('\x04')
switch {
case err == io.EOF || err == io.ErrUnexpectedEOF:
log.Println("Socket closed. EOF / ErrUnexpectedEOF read in")
sockConnected = false
case err == nil:
//log.Println("No error on read")
case strings.HasSuffix(err.Error(), "i/o timeout"):
//log.Println("Timed out read")
default:
log.Println("Some other error occurred.Reason=" + err.Error())
}
if len(readbuf) == 0 {
continue
} else {
//log.Printf("Received from client=%v", string(readbuf))
log.Printf("Recvd Bytes count=%v", len(readbuf))
}
}
从客户端发送到服务器的一个示例数据包:
-
来自客户:
数据发送完成。预期长度= 8267 字节
=> 8268 字节,包括尾随 EOT 字符。
-
在服务器上:
2017/11/08 21:55:42.551604 Recvd Bytes count=1440
2017/11/08 21:55:42.561897 Recvd Bytes count=4096
2017/11/08 21:55:42.569405 Recvd Bytes count=2732
=> 3 个不同的 ReadBytes() 被触发消耗 8268 字节。
=> 第一次和第二次调用返回不同大小的数据。我希望它们是相同的,如果有 1 个单个常量缓冲区用作 bufio 的输入缓冲区。
这里有什么帮助吗?
【问题讨论】:
-
这是 TCP 吗?使用 TCP,从用户空间应用程序的角度来看,没有数据包。无论您认为数据包的排列方式如何,网络堆栈都可以并且将以任何字节数将 TCP 数据传送到您的应用程序。
-
另外,如果您进行大量网络编程,您应该习惯使用 Wireshark 或 Ethereal 或其他网络分析器。例如,在这种情况下,我敢打赌,由于 TCP 启动缓慢、MSS 发现等原因,您将达到 10 毫秒的超时时间。就像这里:en.wikipedia.org/wiki/Path_MTU_Discovery