赞
踩
目录
TCP(Transmission Control Protocol)传输控制协议。顾名思义,就是要对数据的传输进行一个详细的控制。
源端口号和目的端口号是表示数据从哪个进程来,要到哪个进程去。
4位TCP报头长度:表示该TCP头部有多少个32位bit(有多少个4字节);所以TCP头部最大长度是15*4=60.因为4位首部长度可以从0表示到15,而每一个的单位是4个字节,因此该报头长度为60个字节
URG:紧急指针是否有效。
ACK:确认号是否有效。
PSH:提示接收端应用程序立刻从TCP缓冲区把数据读走。
RST:对方要求重新建立连接;我们把携带RST标识的成为复位报文段。
SYN:请求建立连接,我们把携带SYN标识的称为同步报文段。
FIN:通知对方,本端口要关闭了,携带FIN标记的称之为结束报文段。
16位校验和:发送端填充,CRC校验。接收端校验不通过时,则认为数据有问题。此处的检验和包含TCP首部,也包含TCP数据部分。
16位紧急指针:标识哪部分数据是紧急数据。
TCP对数据传输提供的管控机制,主要体现在两个方面:安全和效率。这些机制和多线程的设计原则类似:保证数据传输安全的前提下,尽可能的提高传输效率。
上图中每个ACK都携带了一个确认序列号,意思是告诉发送者,我已经收到了哪些数据;下一次从哪里开始发送数据。
图1 图2
图1这种情况是发送方发送给接收方的数据没有传输到。
有可能是因为网络拥堵的原因没有传输到接收方。
图2是接收方返回的ACK在传输的过程中丢失了。
如果是图2的问题,那么接收端会收到很多相同的数据包,那么在TCP中就会使用到序列号来去除这些相同的数据。
同时这里也涉及到了超时时间,那么在TCP中会动态的设置这个超时时间,在Linux(Unix和Windows)系统中超时时间设置为500ms的整数倍。以指数形式增长,当到达一定阈值后,TCP会认为对端主机出现异常,关闭该连接。
TCP协议在正常情况下要经过三次握手建立连接,四次挥手断开连接。
序号 | 报文路径 | 目的 |
第一次握手 | 客户端->服务器 | 客户端:我发送消息很正常 服务器:我收消息很正常,服务器发消息正常 |
第二次握手 | 服务器->客户端 | 客户端:我收消息很正常,客户端发消息正常 服务器:我发消息很正常,但是此时服务器不知道客户端收消息是否正常,因此需要第三次握手。 |
第三次握手 | 客户端->服务器 | 服务器:我知道客户端也收消息正常 |
三次握手的关键就是确认对方收到了自己的数据包,而这个过程就是通过ACK来实现的。
如果少了第三次握手的情况下,服务器就不知道自己的通信能力是否有问题。
建立连接是很重要,但是及时的断开连接也是非常重要的,否则就会占据不必要的计算资源,如果不能正常断开连接,就会造成数据传输错误,还会造成服务器的压力过大。
通过下表可以看到四次挥手的具体过程:
序号 | 路径 | 目的 |
第一次挥手 | 客户端->服务器 | 客户端申请断开连接。 |
第二次挥手 | 服务器->客户端 | 服务器发送ACK表示我已经收到你发送的内容了。 |
第三次挥手 | 服务器->客户端 | 服务器发送信息表示可以你可以断开连接了。 |
第四次挥手 | 客户端->服务器 | 客户端接收到信息,同时通知服务器,同时断开连接。 |
可以看到,四次挥手和三次握手的图非常相似。
但是为什么第二次和第三次挥手要分开,而不能像第二次握手一样,放在一起呢?
因为当服务器接收到客户端的SYN请求时,可以直接发送SYN+ACK报文。其中ACK是用来应答的,而SYN是用来同步的。
但是在关闭连接时,当服务器接收到FIN报文时,很可能并不会直接关闭SOCKET,因此只能先回复一个ACK报文,通知客户端,我收到了。
只有等到客户端所有的报文都发完了,我才会返回一个FIN报文,因此不可以一起发送。
TCP的三次握手就一定可以保证传输的可靠性吗?
答案是不可以,即使追加再多次握手也不可以使连接更加可靠,因此三次握手足以。
在确认应答机制下,每一个数据段都会返回一个ACK作为应答,但是当数据往返时间较长的时候,就会导致性能比较差,因此TCP就加入了滑动窗口机制。
试想一下,我们之前学习的TCP都是单发单收,发送一个SYN收到一个ACK,然后再发送下一个SYN,那么当数据量增大的时候,这种发送方式是否合理呢?会不会对效率产生一些影响呢?答案是会的。于是TCP在发送的过程中就添加了滑动窗口的机制,比如说,我一次性发送4条SYN,接收方接收到SYN之后,会按照顺序发送ACK回来,当我发送方接到ACK之后,我让窗口向后移动一个位置,继续发送第5条SYN,以此类推,从而可以达到一次发送多条数据的目的,从而大大的提高发送的性能。
但是在发送的过程中如果出现丢包的现象怎么办呢?
1.假如丢弃的是发送端给接收端的报文呢?
假如我第一段报文就丢了,那么发送端就会一直接收到接收端发回的ACK里面可能会这么写(我需要你发送第一段报文过来)连发三次,如果发送端连续三次接收到这个报文,那么就会把这个报文重新发送给接收端,从而实现可靠传输。
2.假如是接收端返回的ACK丢了呢?
比如说,接收端返回的ACK里面写到(我收到了第一段报文)这个被丢弃了,接着又发送了一个ACK(写到我收到了第二段报文)那么此时,发送端就明白了,接收端是收到了第一段报文的,但是返回的ACK丢了(接收端是按照顺序返回ACK报文的,发送端没有收到接收端的ACK报文,是不会让滑动窗口往下继续走的),所以滑动窗口继续往下,正常发送就可以了。
上面讲到了TCP的滑动窗口机制,那么如何控制这个窗口的大小呢?这时候就需要TCP的流量控制和拥塞控制机制了。接受端处理数据的能力不是无限大的,因此如果发送端发送的太快,导致缓存区的数据被塞满,那么就会让后续的数据包被丢掉。因此TCP会根据接受端的处理能力来决定发送端的发送速度,这个机制就叫做TCP的流量控制。TCP会将窗口大小放在TCP报文结构的”窗口大小“字段,从而告诉发送端滑动窗口的大小。
如果缓冲区满了,那么接受端会发送一个ACK给发送端(将窗口设置为0),那么此时接收端将不会发送数据。当过了重发的时间后,发送端会试探性的给接收端发送一个探测窗口。从而得到窗口更新的通知。而且这个探测窗口的发送频率还是很频繁的(主要是怕窗口探测通知的ACK丢包)。
如果说流量控制可以让TCP在传输的过程中实时的知道滑动窗口的大小。那么在刚开始传输之前,如何确定TCP的传输窗口大小呢?
针对该问题TCP加入了慢启动机制,此机制是让少量的数据先去探路,摸清当前的网络状况。再决定以多大的速度传输数据。就像下图一样,窗口先以指数形式增长,到一定程度之后,再按照线性增长,当达到网络拥塞(t1时刻)时就返回到指数增长的时候(不同的TCP协议,可以自定义窗口如何增长,但大多数都是指数+线性),从而再线性增长,寻找到合适的窗口大小。
从以上两个机制就可以控制TCP滑动窗口的大小。
假如说我的缓冲区大小为1MB,但是这次我收到了500kb的数据,那么返回的窗口就是500kb,但是如果我接收端再等等,等下一个数据包,然后一起传输回去,那么此时我传输的就是1MB的数据。这样做的原因是,窗口越大,网络吞吐量越大,效率就越高,而我们网络中主要考虑的就是如何在保证网络不拥塞的情况下最大化的传输数据。
捎带应答就有点像三次握手的第二次一样SYN和ACK可以一起发送回去(参考三次握手)。
那么所有的包都需要延迟应答吗?
不是,一般是隔着N个包应答一次或者过最大延迟时间应答一次,这样是比较合理的。一般N取2,延时时间取200ms。
在以上的这些机制之外,TCP还有面向字节流的特性,缓冲区特性和大小限制的特性。总之一句话:TCP是保证可靠性的传输层的网络协议。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。