TCP流重组的研究

转载自:http://ilovedouzhou.iteye.com/blog/1626183

存储tcp分段的数据结构:一个二维链表,我把它叫作重装表。具有相同socket对(源ip地址、目的ip地址、源端口号、目的端口号)的 tcp数据包放在一个横向的链表里,该链表的头节点只保存了源ip地址、目的ip地址、源端口号、目的端口号这些信息。

然后介绍重装TCP数据段的方法:

1.每到来一个tcp数据包(pkt),我先将该数据包的源ip地址、目的ip地址、源端口号、目的端口号取出来在重装表(tpq_tbl)中纵向的链表中查找有没有与它相匹配的链表(fp)存在,如果有,就把pkt数据包放入与它有相同socket对的fp链中,放入链表的时,我先查找pkt的顺序号在链表中的适当位置,然后才放入;如果没有,则在tpq_tbl中新创建一个该类型的链表头节点,然后再将其放入新创建的链表中。

2.每当在fp中放入一个tcp数据段后,我就检查fp链表中的数据段是否已经到齐了(判断方法下面介绍),若到齐,就将个链表中所有数据段的数据部分拼接到一起,得到应用层报文,然后释放该链表,然后重复1-2步骤;若没到齐,直接重复1-2步骤。

关于判断一个链表中tcp数据段是否到齐的方法:
使用的变量说明:
count计数器,表示当前链表中的所有tcp数据段数据部分的长度之和。每当在该链表中加入一个新tcp数据段时,我都会将count累加上该tcp数据段的数据部分的长度。
syn_seq,表示本次tcp连接的第一个数据包的顺序号,也就是建立tcp连接时的第一次握手的SYN包的顺序号。
fin_seq,表示本次tcp连接的最后一个数据包的顺序号,也就是关闭tcp连接时的第二个FIN包的顺序号。
判断:当(fin_seq - syn_seq)与count相等时,就说明tcp数据段已经到齐,否则就是没有到齐。

 
 

“TCP segment of a reassembled PDU”指TCP层收到上层大块报文后分解成段后发出去。于是有个疑问,TCP层完全可以把大段报文丢给IP层,让IP层完成分段,为什么要在TCP层分呢? 其实这个是由TCP的MSS(Maximum Segment Size,最大报文段长度)决定的,TCP在发起连接的第一个报文的TCP头里通过MSS这个可选项告知对方本端能够接收的最大报文(当然,这个大小是TCP净荷的大小),以太网上这个值一般设置成1460,因为1460Byte净荷+20Byte TCP头+20Byte IP头 = 1500字节,正好符合链路层最大报文的要求。

至于收到一个报文后如何确定它是一个"TCP segment"?如果有几个报文的ACK序号都一样,并且这些报文的Sequence Number都不一样,并且后一个Sequence Number为前一个Sequence Number加上前一个报文大小再加上1的话,肯定是TCP segment了,对于没有ACK标志时,则无法判断。

另外有不太一样的说法,转自http://sabolasi.iteye.com/blog/1254131

MTU和MSS

本文用到的抓包工具为wireshark,它的前身是赫赫有名的Ethereal。wireshark以太网帧的封包格式为:

Frame = Ethernet Header + IP Header + TCP Header + TCP Segment Data

(1)Ethernet Header = 14 Byte = Dst Physical Address(6 Byte)+ Src Physical Address(6 Byte)+ Type(2 Byte),以太网帧头以下称之为数据帧

(2)IP Header = 20 Byte(without options field),数据在IP层称为Datagram,分片称为Fragment

(3)TCP Header = 20 Byte(without options field),数据在TCP层称为Stream,分段称为Segment(UDP中称为Message)。

(4)54个字节后为TCP数据负载部分(Data Portion),即应用层用户数据。

Ethernet Header以下的IP数据报最大传输单位为MTU(Maximum Transmission Unit,Effect of short board),对于大多数使用以太网的局域网来说,MTU=1500。

TCP数据包每次能够传输的最大数据分段为MSS为了达到最佳的传输效能,在建立TCP连接时双方协商MSS值,双方提供的MSS值的最小值为这次连接的最大MSS值。MSS往往基于MTU计算出来,通常MSS=MTU-sizeof(IP Header)-sizeof(TCP Header)=1500-20-20=1460。

这样,数据经过本地TCP层分段后,交给本地IP层,在本地IP层就不需要分片了。但是在下一跳路由(Next Hop)的邻居路由器上可能发生IP分片!因为路由器的网卡的MTU可能小于需要转发的IP数据报的大小。这时候,在路由器上可能发生两种情况:

(1).如果源发送端设置了这个IP数据包可以分片(May Fragment,DF=0),路由器将IP数据报分片后转发。

(2).如果源发送端设置了这个IP数据报不可以分片(Don’t Fragment,DF=1),路由器将IP数据报丢弃,并发送ICMP分片错误消息给源发送端。

关于MTU的探测,参考《Path MTU discovery》。我们可以通过基于ICMP协议的ping命令来探测从本机出发到目标机器上路由上的MTU,详见下文。

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值