我正在Linux下编写一个C / C ++客户端 - 服务器程序。假设消息m将从客户端发送到服务器。
在发送m之前,客户端是否可以读取将携带m的数据包的TCP序列号?
实际上,我想将此序列号附加到m,然后发送生成的数据包。 (嗯,事情更复杂,但让我们保持这么简单。实际上,我想将身份验证信息应用于此序列号,然后将其附加到m。)
此外,
服务器是否可以读取携带m?
的数据包的TCP序列号
答案 0 :(得分:6)
你可以做一些非常接近于此的事情。您可以计算发送的所有字节数,并将消息结束前发送的所有字节数计算在内。
任何人在谈论TCP的'数据包'时,我都会感到非常紧张。因为如果你在谈论数据包和TCP的同时混合不应混合的协议级别。您在TCP中发送的数据与通过IP发送的数据包之间没有任何有意义的对应关系。
是的,IP数据包中有序列号用于发送TCP信息。这些序列号是到目前为止发送的字节数(也称为八位字节)的计数。它们识别数据包中字节所属的流在哪里,但它们与数据包无关。
如果发生重发,或者你正在使用Nagle算法,或者当天的TCP堆栈感觉如此,那么最终可能会有两个发送操作最终在同一个数据包中。或者,最终可能会有一半的发送操作最终在一个数据包中,另一半在另一个数据包中。每个数据包都有自己的序列号。
正如我所说,您在传输层执行的发送操作与在网络层发送的数据包之间绝对没有任何有意义的关系。我理论上也不是在谈论。它并不是“真正的所有数据包下面和发送一般,除非一些奇怪的条件,将所有字节放在一个数据包中”。不,我在上面概述的场景,其中来自单个发送操作的字节被扩展到多个数据包,这种情况经常发生在不可预测的情况下。
所以,我不知道为什么你想知道数据包中的序列号。但是如果您使用序列号作为发送字节数的代理,您可以自己保留该数量,并将其自己填入流中。并记得计算这些字节。
答案 1 :(得分:4)
不,你不能这样做 - 至少不是预期的结果
这是因为:
这意味着您可以在“数据包”末尾发送带有序列号的“数据包”。事实证明,潜在的魔法会重新分割你的数据包。
你想要什么:
1 2 3 4
+---+---+---+---+
| A | B | C |"1"| packet 1, seq=1, len=4
+---+---+---+---+
5 6 7 8
+---+---+---+---+
| A | B | C |"5"| packet 2, seq=5, len=4
+---+---+---+---+
你可能会得到什么:
1 2 3 4
+---+---+---+---+
| A | B | C |"1"| packet 1 (seq=1, len=4)
+---+---+---+---+
(packet 1 got lost)
1 2 3 4 5 6
+---+---+---+---+---+---+
| A | B | C |"1"| A | B | packet 1, resent, seq=1, len=6
+---+---+---+---+---+---+
7 8
+---+---+
| C |"5"| packet 2, seq=7, len=2
+---+---+
答案 2 :(得分:1)
TCP / IP堆栈为您完成所有工作。您只收到有效载荷。堆栈删除所有标头并在用户空间提供有效负载。
如果您确实想要在数据包标题级别添加或修改,请尝试RAW sockets
。无论传输类型(TCP或UDP)如何,RAW套接字都直接从网卡接收/发送数据包。在这种情况下,您必须使用有效负载剥离/添加所有标头(TCP/UDP Header, IP Header and Ethernet Header
)。