tcp协议
tcp报文格式
tcp报文下发时,会被ip报文包裹,如下:
********************************
* ip报文头 * tcp报文头 * 数据 ....
********************************
20字节 20字节
tcp报文头解析
0-15 | 16-31 |
---|---|
源端口 | 目的端口 |
32位的序列号 | 32位确认号 |
4位部首,6位保留,URG,ACK,PSH,RST,SYN,FIN | 16位窗口大小 |
16位校验和 | 16位紧急指针 |
ack:表示确认确认序列
psh:表示提示上级应用尽快消费数据。
rst:连接出现异常时重新连接,
syn:发送tcp握手包
fin:发送挥手包
urg:紧急指针
常见的关键字:
MSS:最大报文段长度
RTT:报文一次往返的耗时
RTO:重传超时时间
MSL:报文最大生存期(Maximum Segment Lifetime)
tcp建立连接
tcp建立连接的过程,三次握手
1.发送方发送一个SYN置位的包,表示这是一个表明这是要给建立连接包
2.接受方拿到包,需要确认接受到这个包,然后也发送一个SYN,tcp协议将这个过程优化,一个包,将SNY,和ACK,同时置位,表示我确认接受到了,并且同意连接。
3.发送拿到步骤2的包后,知道了对方允许建立连接,然后发送ACK,表示连接确认呢。只有tcp建立连接
15:37:26.283762 IP 192.168.3.152.52798 > 192.168.3.160.sunwebadmin: Flags [S], seq 2406610028, win 29200, options [mss 1460,nop,nop,sackOK,nop,wscale 9], length 0
15:37:26.283813 IP 192.168.3.160.sunwebadmin > 192.168.3.152.52798: Flags [S.], seq 2593270431, ack 2406610029, win 29200, options [mss 1460,nop,nop,sackOK,nop,wscale 9], length 0
15:37:26.284134 IP 192.168.3.152.52798 > 192.168.3.160.sunwebadmin: Flags [.], ack 1, win 58, length 0
tcp断开连接
1.发起方发送一个FIN的包,
2.接受方,回应ack先,表示接收到了fin,然后在FIN包表示自己要断开了。
3.发送拿到了FIN后,然后发送ACK。
4.接受方拿到ack断开连接
5.发送方等待2msl后断开,如果不等待万一自己发送的ack丢失,对方会重新传,然后fin,如果自己断开已经断开,就永远没有应带,对方就会一直发送fin
15:35:55.926387 IP 192.168.3.152.52772 > 192.168.3.160.sunwebadmin: Flags [F.], seq 3423229041, ack 2181599064, win 58, length 0
15:35:55.927393 IP 192.168.3.160.sunwebadmin > 192.168.3.152.52772: Flags [.], ack 1, win 58, length 0
15:35:55.927594 IP 192.168.3.160.sunwebadmin > 192.168.3.152.52772: Flags [F.], seq 1, ack 1, win 58, length 0
15:35:55.928486 IP 192.168.3.152.52772 > 192.168.3.160.sunwebadmin: Flags [.], ack 2, win 58, length 0
什么是tcp的滑动窗口
tcp简单描述
tcp发送的数据都是从发送缓存(即一个循环数组 byte[] )中发送,接受方相同byte[];
|窗口左边界 |发送未确认 |窗口右边界
-----------|-----------|---------------------|-----------
| isn| | | | | | | | | | | | | | | | | | | | | | | | |
-----------|-----------|---------------------|-----------
1.isn表示tcp建立连接时初始化的序列号,左窗口左边表示发送了且接受到了另一端发送的ack(ack = isn + 接受的数据长度)。
2.发送为确认,表明发送但是没有收到ack的数据,可能后续接受到ack也可能丢失了。右边界表示最大可以发送的数据的数据序列号。左右边界相减就是窗口大小了。
3.接受方也有一个相似的窗口,如果接受的数据大于窗口的右边界,数据直接丢弃,上层应用处理数据,右窗口右移,接受数据左窗口左移,窗口减小(理解一下一个循环数组,读取过的数据可以丢弃,其实左窗在最左,右在最右,数据写入后,左窗右移,窗口减小。上层应用读取了写入的数据,右窗口一个左窗口的左边。)
滑动窗口带来的好处
- 这样就可以不必每次等待接受到ack,然后发送下一个包。提高效率。
- 接受方也可以通过慢ack,减少自己发送的确认包。(接受方不必马上应答ack,等右数据发送给另一端时,附加ack),这样可以提高网络的利用率。
tcp快速重传
发送端发送包 n1, n2, n3。
但是接受方发送只收到n2,n3所以确认号ack不能确认2,3,只返回n1之前的ack。
当发送给方收到3次相同的ack,表示这个序列号后面的数据丢失。
简单模拟:
发送要发送一个长度位100的数组数据 a[100]
发送到 n1 (a[4],a[5]) n2 (a[6],a[7],a[8]) n3 (a[9],a[10])
接受方收到了 n2,发现没有数据 a[4],a[5] ,返回一个ack 3,表示自己只收到3之前的数据。收到了n3,发现缺少 a[4],a[5],同样返回一个ack 3.
如果收到了相同的三个ack,发送端判断自己应该丢包了。然后发数据重新发送。这些都是在包没有超时的情况下。如果包超时也会重传。
问题: 接受3此相同的ack就会一定丢包吗?
不一定,如果由于路由问题,包到的先后不一样,那么不也会导致ack三次,后面3个包先到,然后‘缺少’包在到,就会出现tcp认为的‘丢包’情况,但是其实没有丢失包。
tcp拥塞控制。
tcp链路的环境是很复杂的。网络环境波动很大。所以tcp的发送数据控制基本都是基于负反馈形式的调节。比如:网络发送时,发现大量丢包(这就是反馈信息),那么将发送的数据量减少,减小网络拥堵情况。
tcp拥塞控制的算法很多,也在不断的迭代优化。下面讨论一下,慢启动算法
慢启动算法
1.慢启动时,开始发送1个最大报文长度的包 拥塞窗口 cwnd =1,然后将数据翻倍 cwnd=2 * cwnd,直到发现大量超时,然后又重新在开始 cwnd=1,发送一个报文。循环往复。
快速恢复
2.优化后慢启动,预先设定一个慢启动阈值,先2的倍数指数增长,发现高于阈值后,按照线性增长,每次增长一个报文大小cwnd = cend +1。当发现超时后,将阈值设置为拥塞窗口cwnd的一半,然后又按照线性增长。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。