计算机网络学习笔记(三)- 传输层(下)

TCP协议

TCP概述

  1. 点对点
    • 一个发送方,一个接收方
  2. 可靠的、按序的字节流
  3. 流水线机制
    • TCP拥塞控制和流量控制机制
    • 设置窗口尺寸
  4. 发送方/接收方缓存
  5. 全双工(full-duplex)
    • 同一连接中能够传输双向数据流
  6. 面向连接
    • 通信双方在发送数据之前必须建立连接。
    • 连接状态只在连接的两端中维护,在沿途节点中并不维护状态。
    • TCP连接包括:两台主机上的缓存、连接状态变量、socket等
  7. 流量控制机制
  8. 序列号:
    • 序列号指的是segment中第一个字节的编号,而不是segment的编号(这里有点不理解,推测是由于每次发送数据在发送之前都是未知的,所以第一个字节编号也可以认为是随机的)
    • 建立TCP连接时,双方随机选择序列号
  9. ACKs:
    • 希望接收到的下一个字节的序列号
    • 累计确认:该序列号之前的所有字节均已被正确接收到(接收端每次收到数据回复ACK,都回复当前接收到的最大序列号的ACK,同时如果回复的ACK序列号大于发送端Sendbase,那么Sendbase也更新为回复的ACK序列号,而不管是否收到小于当前回复ACK序列号的段的ACK,如下图1所示,可见100,120序列号的ACK都已经超时,发送端又重新发送了一次100序列号,但接收端接收到100序列号,只回复序列号120的ACK;如下图2所示,可见虽然没有收到序列号100的段的ACK,但收到了序列号120的段的ACK,Sendbase直接更新为120,即使没有收到段100的ACK)
  1. 处理乱序到达的Segment
    • TCP规范中没有规定,由TCP的实现者做出决策

TCP可靠数据传输

  1. 定时器超时时间设置
    • SampleRTT变化:测量多个SampleRTT,求平均值,形成RTT的估计值
    EstimatedRTT = (1- α) × EstimatedRTT + α × SampleRTT (α = 0.125)
    • 测量RTT的变化值: SampleRTT与EstimatedRTT的差值
    DevRTT = (1- β) × DevRTT +β × |SampleRTT-EstimatedRTT| (β = 0.25)
    • 定时器超时时间的设置:
    TimeoutInterval = EstimatedRTT + 4 × DevRTT
  2. TCP发送方事件
    • 从应用层收到数据
     创建Segment
     序列号是Segment第一个字节的编号
     开启计时器
     设置超时时间:TimeOutInterval
    • 超时
     重传引起超时的Segment
     重启定时器
    • 收到ACK
     如果确认此前未确认的Segment,更新SendBase,如果窗口中还有未被确认的分组,重新启动定时器(每次收到ACK后,都首先看是否能更新SendBase,然后查看当前窗口中是否还有未被确认的Segment,有的话重启定时器)
    • 伪代码如下
	NextSeqNum = InitialSeqNum TCP发送端程序
	SendBase = InitialSeqNum
	loop (forever) {
		switch(event)
		event: data received from application above
			create TCP segment with sequence number NextSeqNum
			if (timer currently not running)
				start timer
			pass segment to IP
			NextSeqNum = NextSeqNum + length(data)
		event: timer timeout
			retransmit not-yet-acknowledged segment with smallest sequence number
			start timer
		event: ACK received, with ACK field value of y
			if (y > SendBase) {
				SendBase = y
			if (there are currently not-yet-acknowledged segments)
				start timer
		}
	} /* end of loop forever */
  1. TCP接收方事件
    • 有序段到达,并且序列号是接收端预期的:在这段之前所有段都已经回复ACK了,那么将等待500毫秒,等下一段到来一起回复ACK,如果到时间了没有下一段,则发送ACK
    • 有序段到达,并且序列号是接收端预期的:配合上一条理解,在这段之前有一段还没有回复ACK,那么回复当前段的ACK
    • 有新的段到来,检测到间隙:立即发送重复的ACK,指示发送预期的字节段(如已经收到了序列100的段了,但段120没到,段130到了,立即发送段100的ACK)
    • 部分或全部填补空白的段的到达:如果段从间隙的下端开始,则立即发送ACK(这句不是很理解)
  1. 快速重传机制
    • TCP的实现中,如果发生超时,超时时间间隔将重新设置,即将超时时间间隔加倍,导致其很大,重发丢失的分组之前要等待很长时间
    • 通过重复ACK检测分组丢失,如果某个分组丢失,可能会引发多个重复的ACK,如果sender收到对同一数据的3个ACK,则假定该数据之后的段已经丢失
    • 快速重传:在定时器超时之前即进行重传
    • 伪代码如下:
	event: ACK received, with ACK field value of y
		if (y > SendBase) {
			SendBase = y
			if (there are currently not-yet-acknowledged segments)
				start timer
		}
		else {
			increment count of dup ACKs received for y
			if (count of dup ACKs received for y = 3) {
				resend segment with sequence number y
		}

TCP流量控制

• 接收方为TCP连接分配buffer


• Receiver通过在Segment的头部字段将RcvWindow 告诉Sender
• Sender限制自己已经发送的但还未收到ACK的数据不超过接收方的空闲RcvWindow尺寸
• Receiver告知Sender此时RcvWindow=0,Sender仍然会发送数据,但会对发送数据进行限制,因为没有发送就没有返回值,也无法了解RecWindow最新情况

TCP连接管理

  1. 建立连接三次握手
    • 第一次握手:
    建立连接时,客户端发送SYN包(包含syn,seq(序列号);syn=1,seq随机假设取a)到服务器,并进入SYN_SENT状态,等待服务器确认;
    • 第二次握手:
    服务器收到SYN包,必须确认客户的SYN,同时向发送端发送SYN+ACK包(包含syn,seq=,ack;syn=1,seq随机假设取b,ack=a+1),此时服务器进入SYN_RECV状态;
    • 第三次握手:
    客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(包含syn,seq,ack;syn=0,seq=a+1,ack=b+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手

  2. 关闭连接四次握手
    • 第一次握手:
    客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号
    • 第二次握手:
    服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间;客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
    • 第三次握手:
    服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
    • 第四次握手:
    客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态;服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。

  3. 为什么连接的时候是三次握手,关闭的时候却是四次握手?
    因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

  4. 为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
    虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。

  5. 为什么不能用两次握手进行连接?
    在谢希仁版《计算机网络》中有一个例子是这样的,“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送ack包。而此时因为client没有发起建立连接请求,所以client处于CLOSED状态,接受到任何包都会丢弃,但server却以为新的运输连接已经建立,并一直等待client发来数据。这样server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。比如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。

  6. 如果已经建立了连接,但是客户端突然出现故障了怎么办?
    TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接

拥塞控制原理

拥塞概述

  1. 非正式定义:太多发送主机发送了太多数据或者发送速度太快,以至于网络无法处理”
  2. 表现:
    • 分组丢失(路由器缓存溢出)
    • 分组延迟过大(在路由器缓存中排队)

拥塞成因和代价

  1. 场景一
  2. 场景二
    条件同场景一,但buffersize是有限的,而不是无限
  3. 场景三
    由图可知,当a发送数据到c时,必然经过两个路由器或者交换机,如果数据在R2处被loss了,那么R2上游的传输能力也将会被浪费掉

拥塞控制方法

  1. 端到端拥塞控制:
    • 网络层不需要显式的提供支持
    • 端系统通过观察loss,delay等网络行为判断是否发生拥塞
    • TCP采取这种方法
  2. 网络辅助的拥塞控制:
    • 路由器向发送方显式地反馈网络拥塞信息
    • 简单的拥塞指示(1bit):SNA, DECbit, TCP/IP ECN, ATM)
    • 指示发送方应该采取何种速率

TCP拥塞控制

基本原理

  1. Sender限制发送速率
    • LastByteSent-LastByteAcked <= CongWin
    • CongWin:动态调整以改变发送速率,反映所感知到的网络拥塞
  2. 感知网络拥塞
    • Loss事件 = timeout或3个重复ACK
    • 发生loss事件后,发送方降低速率
  3. 合理地调整发送速率
    • 加性增—乘性减: AIMD
    • 慢启动: SS
  4. AIMD原理:逐渐增加发送速率,谨慎探测可用带宽,直到发生loss
    • 加性增:每个RTT将CongWin增大一个MSS——拥塞避免
    • 乘性减:发生loss后将CongWin减半
  5. SS原理
    初始时CongWin=1,每个RTT将CongWin翻倍,当达到Threshold时,CongWin转变为线性增长,当达到loss事件时,Threshold被设为Loss事件前CongWin值的1/2,CongWin = 1;

TCP关于loss事件处理

  1. 3个重复ACKs:
    • CongWin切到一半
    • 然后线性增长
  2. Timeout事件:
    • CongWin直接设为1个MSS,然后指数增长
    • 达到threshold后, 再线性增长
  3. 1/2处理的原因
    3个重复ACKs表示网络还能够传输一些segments,timeout事件表明拥塞更为严重
    伪代码如下:
	Th = ?
	CongWin = 1 MSS
	/* slow start or exponential increase */
	While (No Packet Loss and CongWin < Th) {
		send CongWin TCP segments
		for each RTT increase CongWin by *= 2
	}
	/* congestion avoidance or linear increase */
	While (No Packet Loss) {
		send CongWin TCP segments
		for CongWin ACKs, increase CongWin by 1
	}
	Th = CongWin/2
	If (3 Dup ACKs) CongWin = Th;
	If (timeout) CongWin=1;

TCP公平性

  • 如果n个纯粹的TCP服务共享瓶颈链接,则每个最终获得C / n,这是公平的
  • 如果TCP + UDP共享链路,UDP将占用更多带宽,这是不公平的!
  • 如果用户使用多个并行连接(如Web浏览器),即使在纯服务中,也是不公平的!
  • 例子:
    速率R的链路支持9个用户,每个用户使用一个TCP连接
    如果新用户使用11个连接,他将占用11/20的带宽,这对其他用户不公平
发布了14 篇原创文章 · 获赞 0 · 访问量 307

猜你喜欢

转载自blog.csdn.net/wanglizhi3733/article/details/105302897