网络基础知识(二):TCP

1.一个TCP数据报文格式:
这里写图片描述
1)TCP报头通常是20字节,不过有选项可以增加报头长度。由首部长度的4bit可知,最大TCP头长度可达到60字节。
2)Flag共占6位,有6个标记,分别是:
URG——紧急指针(16位的紧急指针式紧急数据的偏移量)
ACK——确认序号有效
PSH——接收方尽快将数据提交给应用层
RST——重建连接
SYN——同步序号发起连接
FIN——发送端完成发送任务
3)接收端如何通过ACK校验数据:如果收到1025~2048字节的报文段校验和错,那么接收方会回复一个确认序号为1025的ACK。
4)我们注意到:TCP和UDP的端口号都放在报头最前面,为什么?
因为:ICMP差错报文返回的数据中,只能包括IP头和产生ICMP差错报文的IP数据报的前8个字节!!!UDP可以放在任意位置,因为UDP报头只有8字节;而TCP报头有20字节,如果放在后面那么返回的ICMP差错报文中只有IP而不包含端口信息了。

2.使用tcpdump观察TCP
使用telnet进行tcp连接,使用tcpdump对产生的tcp数据报进行监控。
a.标识:S为SYN、F为FIN、R为RST、P为PUSH、.为以上四个均为0
b.一个S/P/F的数据报中都包含开始序号、结尾序号和数据长度以及窗口大小,而ack只包含希望收到的序号以及窗口大小。
c.在三次握手的前两次中,都会互相发送mss以确定最大报文长度。以太网最大mss为1460(计算方法:以太网MTU为1500,减去20字节IP头以及20字节TCP头)
d.SYN和FIN都占用一个序号!并且FIN还会发送一个文件结束符(因为发送FIN意味着发送方发送完毕)

3.TCP为什么要有第三次握手
其实正常状态下,两次握手可以完全建立连接,但是设想一种场景:
如果client发送完SYN后没有收到server的ack,client在超时后会重发SYN,而此时这两个SYN都有可能在网络中,server端并不知情,每次收到一个SYN就会回复一个ACK,那么判断这个连接是否有效就要落在client的第三次握手上了,如果已经建立了连接,那么client再收到server的ack时就会将该包丢弃。

4.TCP半关闭
client端完成发送后,即可发送一个FIN(如果只有一个数据报,那么可以将FIN同数据一同发送),即使受到server的FIN ack也并不影响client的接收和回复ack,直到server发送FIN,client才进入timewait状态。

5.TCP状态变迁图
这里写图片描述
6.TIME_WAIT状态(为什么要有第四次挥手?)
TCP中有关网络编程最不容易理解的是它的TIME_WAIT状态。执行主动关闭的那端进入这种状态,该端点停留在这种状态的持续时间是最长分节生命周期(MSL)的两倍,有时候称之为2MSL。 任何TCP实现都必须选择一个MSL值。RFC1122的建议值是2分钟,而源自Berkeley的实现传统上使用的值为30秒。这意味这TIME_WAIT状态的延迟在1-4分钟之间。MSL是IP数据报能在互联网中生存的最长时间。
许多实现MSL为30s,IP首部中的TTL为每个IP数据报规定了生存时间上限:255s或255跳,哪一个先到都会是IP数据报被路由器丢弃。

存在TIME_WATI状态有两个理由:
1) 可靠地实现TCP全双工连接的终止。
2) 允许老的重复分节在网络中消逝。

第一个理由的解释如下:假设TCP连接终止的最终的ACK丢失,服务器将重发最终的FIN,因此客户必需维护状态信息,以允许它重发最终的ACK。要是不维护状态信息,它将响应以RST,而服务器则把该分节解释成一个错误。如果TCP打算执行所有必要的工作以彻底终止某个连接上的两个方向的数据流(即全双工关闭),那么它必须正确处理连接终止序列四个分节中任何一个分节的丢失情况。本例子也说明了为什么进入TIME_WAIT状态的是执行主动关闭的那一端:因为可能不得不重发最终的ACK的是这一段。

要理解存在TIME_WAIT状态的第二个理由,我们假设在12.106.32.254的端口1500和206.168.112.219的端口21之间有一个TCP连接。我们关闭这个连接后,在以后某个时候又重新建立起相同的IP和端口之间的TCP连接。后一个连接称为前一个连接的化身,因为它的IP地址和端口号都相同。TCP必须防止来自某个连接的老的重复分组在该链接已经终止后再现,从而被误解成属于同一连接的新化身。为做到这一点,TCP将不给处于TIME_WAIT状态的连接启动新的化身。既然TIME_WAIT状态持续的时间是2MSL,这就足够允许某个方向上的分组最多存活MSL秒即被丢弃,另一个方向上的应答最多存活MSL秒也被丢弃。通过实施这个规则,我们能够保证每当成果建立一个TCP连接时,来自该连接先前化身的老的重复分组都已在网络中消逝。

所以,当处于TIME_WAIT的主机再次收到FIN时,会回复一个ACK并对2MSL定时器重新计时。

7.FIN_WAIT_2状态无限等待
我们知道,当client收到FIN的ack时会变为FIN_WAIT_2状态,而只有收到server的FIN时才会恢复一个ack并进入TIME_WAIT状态。如果server端一直不发送FIN呢?为了防止无限等待,如果client要执行的是全关闭,而不是半关闭,那么会启动一个定时器,经过10分75秒后超时,直接进入CLOSED状态。

8.异常释放连接,发送一个Rst
双发都不会有多余的响应,而是直接释放连接。使用sock的-L0选项发送RST。

9.服务器忙时,TCP如何处理呼入请求?
1)连接队列:
TCP在内核中维护一个连接队列,这个队列的长度由listen()指定。一般都设置为5,原因:
这个值被称为积压值,它的值对应的是队列的最大连接数,有公式(最大连接数 = 积压值*3/2 + 1)。而积压值得范围是0到5。由公式可知,最大连接数为8。
2)应用层只有在三次握手的第三个报文段接收到后才会知道这个连接。而client回复最后一个ack时表示成功建立连接,这个ack是可能携带数据的,如果此时server应用层还没有处理这个新的连接,那么数据就会被TCP放入缓冲队列中,这也就是TCP滑动窗口的作用了,由于接收方还有数据在缓冲队列中没有被应用进程读取,所以接收方再回复发送方的ack中就会相应的减小win。
3)使用sock模拟连接超时
Sock –O30会让服务器进程在没有接收到任何请求时暂停30s。由于应用进程的暂停并不影响内核中TCP的工作,所以TCP中正常进行三次握手,那么由于应用进程一直没有处理新的连接,就会在连接队列中堆积,当队列满时,TCP就不会处理传入的SYN,也不会回送RST。因为回复client RST会使client的主动连接失败并返回,而不处理的结果就是client不断的超时并重新发送SYN。

另外:由于TCP只有在建立完连接之后才会通知应用进程,所以应用进程是无法对client的主动连接进行干涉的。Server能做的只是FIN或RST,而无论哪个都是建立在已成功连接的基础上的。

10.一次DNS查询要发送多少分组?如果是TCP呢?
一次DNS要有5个查询,如果是UDP是10个分组,而TCP将会是55个。

11.Nagle算法: 减少了广域网传输的小分组数目。
时延确认技术:回复的ACK有一个超时计数器,当小于200ms时间内有其他分组要发送,那么这个ACK就和这个分组合并发送,否则超时后发送ACK。
禁止Nagle算法传输速度会变快,但对网络压力大!

12.滑动窗口协议:
是流量控制方法。由于无须每发送一个分组就阻塞等待确认,从而加速数据的传输。
当接收方回复ack并win为0时,表示接受缓冲区已满,让发送方等待。而当接收方缓冲区有空间时,会发送与上一次ack相同的序号,并更新win大小(窗口每增加2mss或1/2接收方最大窗口时,发送更新窗口ack)。
1) 窗口左边沿向右移动——窗口合拢——数据被发送和确认;
2) 右边沿向右移动——窗口张开——接收应用进程从接收方缓冲区中读出数据;
3) 右边沿向左移动——窗口收缩——不建议使用;
4) 左边沿向左移动——重复的ACK——发送方丢弃。

13.PUSH标志
并不是程序员应用层指定的,而是内核自动添加的。如果当前分组发送后,sendbuf为空,那么当前的分组就自动带有PUSH标志。
例: 发送方要发送8192字节,发送方win(sendbuf)为4096,接收方win(recvbuf)为6144,mss为1024。那么发送方可以连续发送6个1024的分组,而第四个分组将带有PUSH标志。因为发送完4096个字节后,发送方会清空sendbuf然后填充下一次4096字节。

14.连接的理想稳定状态: 发送方同时send和recv,路径上总是具有相同数目的ack。
带宽时延乘积 = 带宽*RTT

15.紧急方式
URG标志位置1,16位的紧急指针作为偏移量与序号相加,计算出紧急数据最后一个字节的序号。只有这个字节被处理完毕才会从紧急状态变为正常状态。
紧急方式作用:当发送方无法发送数据(接收方通知的win为0)时,发送方会发送URG标志和紧急指针,通知接收方应用进程尽快从TCP接受缓冲区中读出数据。

16.对每个连接,TCP管理4个定时器:
1) 重传定时器:每次超时重传的时间都是上一次的2倍,直至64s,最终发送RST。
2) 坚持定时器:当发送方由于接收方的通告窗口为0而阻塞时,如果接收方发送的窗口更新ack丢失,那么就会死锁。为了防止窗口更新死锁,坚持定时器使发送方周期性查询,以发现是否有窗口更新,坚持时间每次*2,直至60s。
3) 保活定时器:如果连接上2个小时没有动作,server就向client发送keepalive分组。
4) 2MSL定时器:测量TIME_WAIT状态的时间。

17.慢启动算法
慢启动增加了TCP另一个窗口:拥塞窗口(cwnd)。
拥塞窗口时发送方的流量控制、通告窗口时接收方的流量控制。发送方取拥塞窗口和通告窗口的最小值作为发送上限。
拥塞窗口初始化为1个mss大小,之后每接收到一个ack就增加一个mss大小,所以从宏观上看,慢启动是指数增长的,但是我们通过tcpdump观察时时一个一个mss增长的(tcpdump每收到一个分组都显示)。

18.拥塞避免算法
作用:处理丢失分组。
和慢启动是不同的算法,但经常结合使用。共同维护两个变量:
拥塞窗口cwnd和慢启动门限ssthresh。
工作过程:
1) 初始化cwnd为1个mss大小,ssthresh为65535个字节。
2) 当拥塞发生时(重传定时器超时或连续收到三个重复的ack),ssthresh被设为当前窗口的一半(当前窗口为cwnd和通告窗口的最小值),但最小为2个mss;但如果是超时引起的拥塞,则直接将窗口设为1mss,即直接变为慢启动!
3) 发送方每收到一个ack就将cwnd加1,直到cwnd大于ssthresh。所以,在cwnd小于等于ssthresh时,是慢启动方式,指数增长;而大于ssthresh后使用拥塞避免增长方式:每收到一个ack,将cwnd加1/cwnd大小,即变为线性增长,不管在当前RTT中受到多少ack每次最多允许cwnd加1。

19.快速重传和快速恢复算法
快速重传:连续收到3个重复的ack就重传丢失的数据报,无须等待重传定时器溢出。
快速恢复:快速重传后不执行慢启动,而是执行拥塞避免算法。
工作过程:
1) 当收到三个重复的ack时,将ssthresh设为cwnd的一半(最小2个mss),将cwnd设为ssthresh加3个mss大小。
2) 使用拥塞避免的方式,而不是慢启动。即快速恢复。
3) 快速重传后的连接,在发送端再接收到重复ack的时候允许cwnd加1。而快速重传之前是不允许的。

为什么快速重传后使用拥塞避免,而不是慢启动?
接收方回复连续重复的ack,说明除了丢失的分组外,其余的分组都是正常发送并存入接收方的缓冲区的,所以当前两段之间仍然有流动的数据,此时如果执行慢启动,会使数据流突然减小,不是我们想看到的。

为什么快速重传后,再接收到重复ack就允许cwnd+1了?
其实接收方回复重复的ack,只是说明丢失了该分组,并不影响整个连接的流量,所以执行快速恢复算法时允许cwnd+1,而在快速重传算法触发前快速恢复算法也不会触发,所以是不允许cwnd+1的。

什么情况下会产生重复ack?
1) 丢失该分组
2) 由于网络时延导致的接收方收到的分组顺序发生改变。例如:
发送方发送:1、2、3、4
接收方收到:1、3、2、4时,就会产生一个序号为2的重复ack;而如果接收方收到:1、3、4、2时,就会产生序号为2的两个重复ack。
注意:3和4两个分组都被接收方缓存在recvbuf中,直到收到序号为2的分组,一起回送序号为5的ack并通知应用进程将数据读取出去。

只有重传才会改变ssthresh值,而重传有两种方式: 超时重传和快速重传。

20.TCP遇到的常见ICMP差错
1) 源站抑制:引发超时重传,cwnd置1,触发慢启动,但ssthresh不会产生变化。
2) 主机不可达:忽略。坚持重传。直至64s间隔重传后,发送RST。
3) 网络不可达:忽略。坚持重传。同上。

21.TCP的重新分组
TCP超时重传时,不一定发送相同的分组,可以将较小的分组合并后发送。因为TCP是流传输,依靠的是字节序号,而不是分组序号。

22.TCP的keepalive定时器:
如果一个连接在2小时内无动作,server会发送该分组。Sock –K是保活选项。
Client有以下4中状态:
1) Client主机正常运行,server可达。
2) client主机崩溃,已经关闭或正在重启。Server会连续发送10个keepalive探查,间隔75s。
3) client主机崩溃,并已经重启。Server会收到一个RST相应,终止连接。
4) client主机正常运行,但server不可达。与2)相同。

我们可以修改keepalive定时器的2小时变量,但由于该功能是TCP内部工作的,是内核态的,如果当前应用程序修改了定时器,其他的所有的使用TCP服务的程序也会收到影响!

23.TCP的keepalive选项的优缺点
优点:1)比应用层keepalive报文占用更少的带宽(该报文不含任何数据);2)只有在空闲时才会发送探查报文。
缺点:报文的探测时间不能随意修改(由于是内核态的,影响其他应用)。

24.TCP路径MTU发现机制
建立连接时,TCP使用client和对端的MSS中的最小值作为起始报文段大小,如果对端没有声明,默认mss为536。(注意这里的对端并不一定是server,而是路径上的下一个节点)

具有DF选项的数据报不能分片,如果分片,产生ICMP报文差错。

注意:分组大使带宽利用率变大,但并不是分组越大就越好。由于分组越小,数据报也越多,相对而言,链路的空闲时间就少。(详见TCP/IP详解P259)

25.TCP在长肥管道中的问题
1) 窗口大小限制:TCP中窗口大小为16bit,所以最大65535。
2) 长肥管道中分组丢失是吞吐量急剧减少。
3) TCP对每个窗口的RTT只进行一次测量。
4) 序号回绕问题:32bit的无符号序号,最多2的32次方,即40亿个。而MSL,即最大报文生存时间内,如果序号发生回绕,那么就废了啊!!!我们知道TTL最大可以达到255s,而一个千兆比网络(1000Mb/s)中34s就会发生回绕!!!(4G*8/1000M=34s)

解决:
1) 窗口扩大选项可以扩大14bit,从而可以使窗口变为2的30次幂大小。
2) 时间戳选项可以解决RTT问题。
3) PAWS算法:防止回绕的序号。

26.基于TCP的事物协议:T/TCP
TCP为实现事物需要进行两个改动:避免三次握手、缩短TIME_WAIT状态时间。
使用加速打开避免三次握手方法:
Server为每个client维护一个32bit的计数值CC,如果收到的CC值大于缓存的,说明是SYN是新的,可以直接接受数据;如果收到的CC值小于缓存的或没有保存该client的CC值,那么就进行三次握手。这个方法的缺点就是要付出维护每个client的32bit数的代价。
将TIME_WAIT时延设为8倍的重传超时值RTO。

通过上述修改,最小的事物序列只包含三个数据报(TCP是11个:3+4+4=11):
1) Client: SYN、数据、FIN、CC;
2) Server: SYN、FIN的ack(由于TCP确认是积累的,所以这个ack包含了对SYN、数据的确认)、FIN、CC以及客户CC的CCecho;
3) Client: FIN的ack(包含了SYN的ack)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值