【发布时间】:2022-01-22 17:01:58
【问题描述】:
我已经用 C++ 构建了一个 UDP 服务器,对此我有几个问题。
目标:
我有传入的 TCP 流量,我需要将其作为 UDP 流量进一步发送。然后我自己的 UDP 服务器处理这个 UDP 数据。 TCP 数据包的大小可以变化。
详情:
在我的示例中,我有一个总共包含 2000 个字节 (4 random bytes, 1995 'a' (0x61) bytes and the last byte being 'b' (0x62)) 的 TCP 数据包。
我的 UDP 服务器有一个大于 2000 字节的缓冲区 (recvfrom buffer)。
我的 MTU 大小到处都是 1500。
我的服务器正在正确接收此数据包。在我的 UDP 服务器中,我可以看到接收到的数据包的长度为 2000,如果我检查最后一个字节 buffer[1999],它会打印 'b' (0x62),这是正确的。但是如果我打开tcpdump -i eth0,我只会看到一个UDP 数据包:09:06:01.143207 IP 192.168.1.1.5472 > 192.168.1.2.9000: UDP, bad length 2004 > 1472。
使用tcpdump -i eth0 -X 命令,我看到了数据包的数据,但只有~1472 字节,其中不包括'b'(0x62)字节。
ethtool -k eth0 命令打印udp-fragmentation-offload: off。
所以我的问题是:
- 为什么我只看到一个数据包而不是两个数据包(片段 1 和 2)?
- 为什么我在 tcpdump 中看不到 'b' (0x62) 字节?
- 在我的 C++ 服务器中,最好使用什么缓冲区大小?我现在在 65535 上拥有它,因为传入的 TCP 数据包可以是任意大小。
- 如果大小超过 65535 字节会发生什么,我是否必须在将 TCP 数据包作为 UDP 发送之前制定自己的分片方案?
【问题讨论】:
-
TCP 是基于流的,像 'TCP 数据包' 这样的东西不存在。实际上,底层传输 (IP) 是基于数据包的,但这些数据包会尽可能地被填满,然后发送(如果有足够的数据可用)——很容易在一个数据包中获得多个自定义协议数据包从流或部分包中读取。如果你想要一个基于 TCP 的基于数据包的协议,你需要自己实现一个合适的分离算法!
-
我已经在多个场合使用COBS 来实现此目的——并结合每条消息包含的 CRC。您通过零字节分隔消息,CRC 确保 - 除了捕获传输错误 - 如果您不小心从填充的原始零字节开始接收,您可以检测到部分消息......
-
您知道 MTU 还计算数据包标头...对吗? MTU 为 1500 时,UDP 数据包,包括标头和所有内容,不能大于 1500 字节...尝试发送不大于 1460 的 UDP 有效负载...甚至更好,限制有效负载到 1350 字节,就像 QUIC 一样。
-
为什么需要切换协议?仅将 TCP 数据作为 TCP 转发可以使整个内容更不容易出错(尽管您仍然需要在第二个服务器上分离单个消息)。有两台服务器的原因是什么?将两者结合在一个服务器中可能会导致设计不那么复杂。
-
有史以来最好的防火墙:禁止通信:D
标签: c++ sockets networking udp