目录
概述
运输层端口号、复用与分用的概念
概念
发送方的复用和接收方的分用
- 这个理解起来比较容易,TCP复用就是发送方封装时可以多个应用用TCP协议,UDP同理;分用的时候就是把接收方数据分发给多个应用。
举例
- 如下图,用户想要访问www.porttest.com,但是用户pc并不知道该网址所对应的ip地址,所以路由器无法转发,用户PC就得先用DNF进程发送一个DNS查询请求(DNS使用UDP协议),UDP首部的目的端口必须是53,因为53是DNS进程的端口,源端口就是从短暂端口号随机分配的一个,这里是49152,这样,就能将此次UDP报文发送到DNS服务器解析了。此时用户PC的DNS进程短暂端口号为49152
- DNS服务器收到UDP报文后解析UDP首部,发现目的端口是53,于是就调用DNS进程解析www.porttest.com的IP地址
- 解析完后,将数据封装成UDP报文相应给用户PC,此时用户PC发现目的端口是之前DNF短暂端口49152,于是调用DNS进程解析该UDP报文段就可知web服务器IP地址是192.168.0.3
- 此时,用户PC就可以发送通过HTTP进程发送HTTP请求到Web服务器了,HTTP请求使用TCP协议。此时HTTP进程的短暂端口号是49152
- web服务器收到HTTP请求后,发现目的端口是80,于是调用HTTP进程解析,直到用户要请求首页内容,于是将首页内容封装成HTTP报文响应给用户PC
- 用户PC收到响应后发现目的端口是之前使用的HTTP短暂端口49152,于是解析后将信息展示在网页中
UDP与TCP的对比
- 数据传输UDP不需要连接;而TCP需要三握连接,四挥释放连接,三握四挥比较复杂,后面会专门讲
- UDP支持单播、广播、多播;TCP由于需要连接,仅支持单播
- UDP是面向应用报文的;而TCP是面向字节流的,这也是流量控制、拥塞控制、可靠传输的基础
- 网际层(网络层)之前有讲过了,向上层提供的是无连接不可靠传输服务,UDP向应用层提供的还是无连接不可靠运输服务,因此使用于一些实时应用,视频会议、ip电话等;而TCP向应用层提供的是面向连接的可靠传输服务,适用于文件传输等需要可靠传输的应用
- 两者首部格式对比
- 小结
TCP的流量控制
概述
举例
- 如下图,发送方刚开始窗口是400字节,现在每次发送给B100字节,当B接收到数据后,会对A发送确认数据并调整窗口大小
- 注:seq表示发送数据的第几个字节开始;大写ACK=1表示确认位,小写ack=201表示对201号以前的数据进行了累计确认;rwnd=300就是流量控制,表示接收方把接收窗口调整为300。
- A接收到主机B对前200个字节确认后,先将自己窗口往右滑动200字节,又接收到B调整为窗口300后,将自己的窗口也调整为300,接着发送剩余的200字节数据,这时候201-300数据重传计时器超时了,超时重传旧的数据,此时窗口内数据已经全部发送完,不能再发送新的数据;B收到全部数据后,发送确认数据,并对A进行第二次流控,此时窗口调整为100.
- 上面窗口调整为100后,A此时就只能发送100字节数据,B收到这100数据后,对A第三次流控,窗口调整为0,至此,A不能再发送新数据了。
- 死锁局面,B此时又有了接收缓存,想通告主机A,但是这个通告信息丢失了,A就一直等待B的非零窗口通知,B也一直在等待A发送的数据,此时就形成了死锁局面
- 解决方案,窗口被调控为0就会启动一个持续计时器,当持续计时器超时后,会发送一个零窗口探测报文,询问B是否有存储空间。
- 下面的rwnd=300就是一个例子,此通告丢失了,但是并不会死锁;因为持续计时器超时后,A发送了零窗口探测报文,此时B的存储空间又为0了,但是没事,A再次启动持续计时器,再次超时后发送零窗口探测报文,B此时存储空间有300,发送rwnd=300给A,打破死锁局面。
- 注:下面有个问题,零窗口探测报文丢失了怎么办?问题不大,因为零窗口探测报文也有重传计时器,如果太久没收到会重发零窗口探测报文。还有个问题:不是B已经没空间了吗,怎么还能接收零窗口探测报文?这其实是规定,无论何时,都必须接收一些特殊的报文,零窗口探测报文就属于特殊报文的一种。
- 例题(拥塞还没讲,下面就直接给出刚开始发送窗口是4000)
TCP的拥塞控制
概述
- 吞吐量可以理解为输出
慢开始算法和拥塞避免算法
- 慢开始算法要设置一个慢开始门限值ssthresh,下面中设置为16,cwnd拥塞窗口设置为1,swnd发送窗口=cwnd,cwnd是指数型增长,只要收到确认就增长
- 下图首先发送了报文段0,接收方也发送了确认
- 收到报文段0的确认后,cwnd指数增长,此次增加2的0次方,此时发送窗口为2,可以发送2个报文段
- 发送2个报文段收到确认后,cwnd指数增长,此次增加2的1次方,此时发送窗口为4,可以发送4个报文段
- 发送4个报文段收到确认后,cwnd指数增长,此次增加2的2次方,此时发送窗口为8,可以发送8个报文段
- 发送8个报文段收到确认后,cwnd指数增长,此次增加2的3次方,此时发送窗口为16,可以发送16个报文段,达到慢开始门限值
- 达到慢开始门限值,转用拥塞避免算法,每次cwnd只增加1
- 在这样经过几轮的拥塞避免算法增加cwnd后,突然有一次报文段丢失了
- 此时发送方未收到确认,超时重传计时器超时,但是发送方并不知道是网络拥塞还是报文丢失,统统认为是网络拥塞,拥塞避免算法将ssteesh值更新为当前发生拥塞cwnd的一半,也就是24/12,再将cwnd拥塞窗口减为1,重新开始执行慢开始算法。
- 至此,就是慢开始算法和拥塞避免算法的一个工作原理了,从中也能看出问题,报文丢失被误认为拥塞,重新从1开始,传输效率变慢,所以有了快重传和快恢复
- 小例题
快重传和快恢复算法
- 下图演示是快重传,发现丢失或错误,在超时重传计时器超时前就进行重传,趁超时重传计时器不注意(doge)
- 下面是快恢复,快恢复就是将慢开始门限降为当前窗口一半的同时,cwnd也是降为当前窗口一半,而不是直接降到1
慢开始、拥塞避免、快重传、快恢复 演示图
TCP超时重传时间的选择
TCP可靠传输的实现
- TCP不建议窗口缩小
- 例题
TCP的连接管理
概述
- 注意:读者在本节中对一些什么seq序号、ack确认号、ACK确认标志位等不太理解,没有关系的,在下一节中笔者会介绍这些符号标志,或者读者先到下一节“TCP报文段首部格式”阅读完再回到此节也是可以的。
TCP的连接建立(三报文握手)
- 刚开始客户端和服务器处于关闭状态,两端并没有建立连接,服务器端会一直监听客户端发送的TCP连接请求,这个称为被动打开
- 第一次握手:客户端发送TCP请求连接,并进入同步已发送状态,SYN=1表明这是一个TCP连接请求报文段,seq是TCP进程所选择的初始序号(TCP就是靠序号滑动窗口保证可靠传输的),这里先用x表示;这一步叫做客户端主动打开。 注:TCP规定SYN=1的报文段不能携带数据,但是要消耗一个序号
- 第二次握手:服务器端发送TCP连接请求的确认并进入同步已接收状态,SYN=1和ACK=1(TCP确认报文段)表明这个一个TCP连接请求确认报文段,seq作为TCP服务器进程所选择的初始号,这里用y表示,确认号ack=x+1表明对TCP客户进程所选择的初始化序号的确认
- 第三次握手:客户端发送TCP确认报文段并进入连接已建立状态;ACK=1表明这是一个普通的TCP确认报文段,seq=x+1是因为第一次握手使用的序号是x,按顺序下来就是x+1了,ack=y+1表明是对TCP服务端进程所选择的序列号作确认。 注:TCP规定普通的TCP确认报文段是可以携带数据的,携带数据需要消耗一个序列号,不携带则不消耗
- 服务端接收到客户端发送的TCP确认报文段,进入连接已建立状态,至此,客户端与服务器端建立了全双工通信连接
- 第三次握手是否多余?两次握手可不可以?请见下面解释。
- 下面这是两次握手的情况,服务器端去掉同步已接收这个状态,收到TCP第一次连接请求就进入连接已建立,然后发送TCP连接确认给客户端,客户端也进入连接已建立状态,双方全双工通信。
- 至此,好像没什么问题,两次握手也能够正常通信。
- 问题来了,下图第一个TCP连接请求,因为网络问题,在某个网络节点滞留了许久,第二个TCP连接请求已经与服务器建立完连接并且释放了,此时客户端和服务器端都是关闭状态;这时,第一个TCP请求,他竟然到了(好家伙,迟到一个世纪),这时候服务器端马上进入连接已建立状态,并且向客户端发送TCP连接确认报文,客户端此时是关闭状态,直接不鸟服务器端,这样就导致服务器端一直在连接已建立状态,苦苦等不可能发送数据的客户端,造成了资源浪费。
- 注意:有个点上面没说,如果第三次握手失败,根据《计算机网络》书本描述,服务器并不会重传ack报文,而是直接发送RST报文段,进入CLOSED状态。这样做的目的是为了防止SYN洪泛攻击。
TCP的连接释放(四挥手)
- 第一次挥手:TCP客户端发送TCP连接释放报文并进入终止等待1状态,FIN=1(终止位)和ACK=1(确认位)表示这是一个TCP连接释放报文段,同时也对上次收到的报文段进行确认;seq=u表示TCP客户进程已经传送到服务器的数据的最后一个字节序号+1;ack=v表示TCP客户进程已经收到的服务器数据的最后一个字节序号+1
- 第二次挥手:服务器发送TCP确认报文并进度关闭等待状态,并且通知应用进程;ACK=1表示这个是一个普通确认报文;seq=u表示TCP服务器进程已经传送到客户端的数据的最后一个字节序号+1;ack=u+1表示对TCP连接释放报文段的确认
- 二挥手客户端收到TCP确认报文段后进入终止等待2状态,这时候TCP处于半连接状态;客户端进程已经没有数据再发送了,但是服务器进程如果还有数据要发送,客户端进程仍然要接收数据
- 第三次挥手:TCP服务器进程这时候已经没有数据需要再发送了,于是通知TCP服务器释放连接,TCP服务器就发送连接释放报文段,并进入最后确认状态;FIN=1和ACK=1表示这是一个TCP连接释放报文段;seq之所以等于w,不等于之前的v,这是因为在半连接状态服务器端进程还有可能发送新数据,seq是表示TCP服务器传送到客户端进程的数据的最后一个字节序号+1,之前已经说过了;ack=u+1就是对之前的TCP客户进程报文的重复确认。
- 注:因为此次释放连接是TCP服务器进程发起的,我们叫他被动关闭,客户端的就叫主动关闭;
- 第四次挥手:TCP客户端进程发送TCP普通确认报文段并进入时间等待状态,2MSL后关闭,TCP服务器收到该报文段后直接关闭连接;ACK=1表示这是一个TCP普通确认报文段,seq=u+1是因为在一挥手的时候,发送的报文段消耗了一个序号,FIN是会消耗序号的,第一次seq=u,那这一次理所当然是u+1,ack=w+1是对TCP服务器的报文段确认。
- 延申出来一个问题:四挥后有必要等待2MSL吗?直接关闭连接不就行了吗?请往下看。
- 问题解释,不等待出现的问题。
- 如果TCP客户端四挥没有时间等待直接关闭连接,这时候第四次挥手的确认报文段丢失了或者出现其他原因无法到达TCP服务器端,TCP服务器端没收到确认,必然超时重发,但是由于客户端关闭了,重发几次客户端都接收不到,就导致服务器端无法关闭连接,这就是为什么四挥后还要进行时间等待。
- TCP数据传输出现故障,有个保活计时器来让服务器端发现故障,进而关闭连接。
TCP报文段的首部格式
概述
源端口和目的端口
- 源端口和目的端口这个很好理解,光是看图就能够懂了
- 下图中客户端发送请求到web服务器,源端口49152是短暂端口为应用进程分配的一个号,目的端口是web服务器接收请求应用进程的端口号;发送到web服务器后,web服务器根据目的端口调用进程来作相应处理,然后响应到客户端,源端口自然就是当前80进程的端口,目的端口就是客户端应用进程那个分配的短暂端口号。
- 客户端收到后就解析数据展示到网页中
序号、确认号和确认标志位ACK
- 序号就是之前讲三握四辉那个seq,表示当前TCP报文段数据载荷中第一个字节的序号
- 确认号就是之前讲三握四挥那个小写ack,表示希望收到对方下一个TCP报文段数据载荷的第一个字节序号,同时也是对之前收到的所有数据的确认
- 比如:对方seq=x,只发送了1个报文段,那这收到我们收到了x,我们下一次想收到的报文段就是x之后的,即x+1,那此时ack=x+1
- 确认标志位ACK,见下解释,=1就完事了
- 来看一个小例子:客户的TCP报文段序号是201,数据载荷长度100字节,即发送了第201-300字节的数据,确认号800:表示服务器下次发送的数据应从800开始;
- 此时服务器接收到了数据,服务器确认了201-300字节的数据,服务器下一次要客户端发送的数据就是301开始了,所以确认号为301,序号为800正是对应了客户端发送过来的确认号
数据偏移
- 用于指出TCP报文段的数据载荷的起始处举例TCP报文段的起始处有多远,那说白了就是TCP报文段的首部长度
- 注意:这个的单位是4字节,例如下面的0101换十进制是5,单位是4字节,那就得5*4=20;1111换十进制是15,那就得15*4=60
保留
- 不知道有什么卵用
窗口
- 这个重要性大家都知道,前面讲的滑动窗口大小就是这个来标识的
检验和
同步标志位SYN
- 有SYN表示这是一个TCP连接请求报文段
终止标志位FIN
- 有FIN表示这是一个TCP连接释放报文段
复位标志位RST
- TCP连接异常或者三握手中出现异常用RST直接复位,然后要想重新连接就还是再三握