DIY TCP/IP TCP模块的实现7

上一篇:DIY TCP/IP TCP模块的实现6
9.9 TCP滑动窗口的实现1
9.1节介绍TCP头部结构时,已经介绍过TCP头部的window size是本地TCP连接的接收缓存大小。TCP的接收方通过window size把接收缓存的大小告知发送方。TCP发送方根据接收方的window size发送数据,以确保接收方有足够的缓存存放数据。TCP通过滑动窗口管理发送缓存和接收缓存。DIY TCP/IP目前没有编译成动态库被其他程序调用,只是做为TCP的接收方独立运行,所以本节介绍的TCP滑动窗口是DIY TCP/IP做为TCP的接收方,管理接收缓存的实现,做为发送方时的滑动窗口的实现在后续章节扩展。
先来看一下DIY TCP/IP滑动窗口的数据结构图
DIY TCP/IP Slide Window
TCP头部中,window size占两个字节。9.4节实现TCP连接的初始化时,在tcp_conn_open函数中,将本地TCP连接的接收缓存window size设置为65535,window scale设置为8,即本地TCP连接的接收缓存为65535 * 256 = 16MB。
上图将接收缓存分为三个部分,蓝色部分是接收缓存中可以存放接收数据的剩余空间。红色部分是确认过的数据,代码实现时模拟一个读取数据的线程,从红色部分读取数据,读取后的数据从红色变为蓝色。绿色部分是已经收到但尚未发送确认的数据。虚线框的sliding window中既有绿色部分,又有蓝色部分,接收到数据帧时按字节顺序存放在蓝色部分,蓝色分变为绿色。TCP模块发送确认后,绿色部分变为红色部分。随着数据帧的接收,确认和读取,蓝色变为绿色,绿色变为红色,红色变为蓝色,相当于虚线框向右滑动一样。
图中箭头指向的位置均为指针,buffer start指向接收缓存的第一个有效的字节,buffer end指向接收缓存的末尾字节的下一个字节,buffer end - buffer start = 16MB。
Received Start指向接收但尚未确认的数据的第一个字节,received end指向接收但尚未确认的数据的末尾字节的下一个字节,即接收到的数据按字节从received end字节处开始存放。
Ack start指向可以被读取线程提取的第一个字节,ack end指向可被提取的末尾字节的下一个字节,即receive start字节处。图中的指针移动越过buffer end后,均会回绕到buffer start继续开始。回复ack时,计算接收缓存剩余空间的大小,上图中acked_start已经发生过回绕(acked start < received end),所以(acked start + 16M) - received end即为剩余的接收缓存的大小。Sliding window 初始化时箭头位置的指针均指向buffer start字节处。
实现滑动窗口之前,先通过tcpdump抓包,分析一下TCP数据帧的接收过程。抓包时主机A (192.168.0.110)运行iperf TCP的server端,命令为”iperf -s -i 1”,主机C(192.168.0.111)运行iperf TCP的client端,命令为”iperf -c 192.168.0.110 -i 1 -t 43200”。tcpdump是在主机A上抓取eth0接口的数据帧,命令为”tcpdump -i eth0 -s 0 -w ~/Desktop/tcp_data.pcap”。在wireshark中打开tcp_data.pacp。
DIY TCP/IP tcpdump iperf
序号为11,14和15的数据帧是TCP的三步握手数据帧,序号为15到25的数据帧是TCP数据帧和TCP ACK。可以看出主机C(192.168.0.111)每向主机A(192.168.0.110)发送一个TCP数据帧,主机A就回复一个TCP ACK。主机A的TCP ACK是不携带数据的,将序号为15到25的数据帧展开为图示
DIY TCP/IP TCP data packet flow
图中蓝色标注的数据帧由主机C (Iperf TCP Client)发出,红色标注的数据帧由主机A(Iperf TCP Server)发出。关注主机C的sequence bumber,主机A的ack number的变化,以及主机A的window size的变化。11,14,15是三步握手数据帧,从第16帧开始,主机C开始向主机A发出携带数据的TCP数据帧,观察主机C发出的TCP数据帧,均带有ACK标志,这表明主机C在发送数据的同时捎带确认主机A发出的TCP ACK。
主机A每收到一个TCP数据帧,均向主机C回复TCP ACK,红色标注的TCP数据帧携带的数据长度Len=0,主机A只是回复TCP ACK,没有携带数据,所以主机A发送的TCP ACK的sequence number均为1。由于TCP ACK没有携带数据,所以主机C确认收到TCP ACK时回复的携带了数据的ACK的acknowlegdge number均为1。
再来看主机A的window size的变化,主机A是iperf TCP Server,window size从第17帧的227,逐渐增加到第25帧的317,这里的window size都要乘上128才是接收缓存的大小。主机A window size的变化用于控制主机C(iperf TCP Client)的TCP慢启动过程。下节实现滑动窗口时,简化处理winow size的值,按照本地TCP连接的接收缓存的实际大小填充该字段,即本节介绍的滑动窗口数据结构中的蓝色部分的大小。
主机C发出的第一个TCP数据帧携带的数据长度为24,其他TCP数据帧携带的数据长度为1448,1448加上32个字节的TCP头部(包含12个字节的TCP选项)和20个字节的IP头部是1500,再加上14个字节的以太网头部共1514字节,即wireshark中显示的主机C发出的第18,20,22,24帧的长度,第16帧的长度计算方法也是一样。主机A发出的第17,19,21,23,25帧(TCP ACK)在wireshark中显示的长度均为66,即32个字节的TCP头部(包含12个字节的TCP选项),加上20个字节的IP头部,再加上14个字节的以太网头部。主机C发出第18帧,TCP的sequence number为1,携带的数据长度为24,主机A发送第19帧,ack number为25 = 1 + 24,是对第18帧的确认,表明希望收到序号为25开始的数据。主机C再发出第20帧,sequence number为25,携带的数据长度为1448,主机A再发出第21帧,ack number为1473 = 25 + 1448。后续主机C和主机A发出的数据帧的sequence number和ack number的计算方法类似。
下一篇:DIY TCP/IP TCP模块的实现8

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值