本篇主要讲解TCP协议报头的各个字段,在讲解字段的过程中引出TCP的各种机制。
TCP协议的报文格式
1. 源端口号和目标端口号
源端口号:表示报文的发送端口,占16位。源端口和源IP地址组合起来,可以标识报文的发送地址。可以理解表示为数据从哪个历程来的。
目标端口号:表示报文的接收端口,占16位。目标端口和目标IP地址相联合,可以标识报文的接收地址。可以理解为表示数据要去到哪个历程。
2. 4位首部长度
4位首部长度是用来表示TCP报头长度的。TCP报头是可变的,一般由选项决定;标准的TCP报头(没有选项)是20字节。
4位首部长度的范围为[0,15],但是这只是数值,不是报头的实际大小,4位首部长度是由单位的,单位是int或者4字节;实际范围为[0,60];
4位首部长度是多少取决与选项。例如,没有选项,报头的实际大小是20字节,根据4位首部长度单位,推出数值应该为5, 4位首部长度就是0101。
3.序号和确认序号
确认应答(ACK)机制:
起首要理解确认应答,客户端给服务端发送报文,只有服务端发送一个回应(报文),才能确认收到上一条报文;又要让客户端确认是否收到,又要再发一个回应(报文),要确认就会一直如许循环下去。
所以,发送回应报文,只能确认上一步,进一步说,只能确认历史报文的接受,下一步或者现在我们不能确定!
实际上的通信,是客户端发送了几个请求,服务端一起回应,这个回应有先后次序,而且怎么确认哪个请求被回应?TCP是通过序号的,每个请求都有一个序号,回应的报文必要把对应的序号+1。如许就解决了请求是否被回应,以及回应多个请求时的辨别问题。
捎带应答机制的初识:
实际的应答不仅仅是确认上一个报文以及收到,也大概会必要发送数据,与这次应答一起发送给对方。因此,既必要一个序号用来确认对方的报文,本身也要有序号来发送本身的报文。这就是TCP的序号与确认序号。
总结:序号保证报文能够按序到达,确认应答;确认序号和序号保证同时进行应答和发送数据。
3.TCP面向字节流:
TCP协议下的发送和接受缓冲区,存储单位是字节;于是把字节的下标看成序号,如许每个字节就有序号了。
4.控制标记
控制标记是用来区分报文范例的。报文范例有建立毗连的报文、发送数据的报文和断开毗连的报文等。
常见的标记位SYN:表示该报文请求建立毗连或者请求接受报文。
ACK:表示接受报文成功,并且该报文包含确认序号。
FIN:表示该报文请求断开毗连
其他:
URG: 紧急指针是否有效 PSH: 提示接收端应用程序立即从 TCP 缓冲区把数据读走 RST: 对方要求重新建立毗连 ; 我们把携带 RST 标识的称为 复位报文段 超时重传机制:
发送报文后,大概碰到的情况:报文没送到丢失,甚至报文送的太慢;收到报文,应答丢失,或者应答太慢甚至对方不应答。
为相识决上述情况,TCP定义了 超时重传机制。发送了报文,在特定时间内没有收到应答,一律视为丢包,并进行重新发送。
如果出现对方只是应答有问题,报文收到了,由于报头有序号的缘故原由,可以识别重复的数据进行去重。
超时时间的确定:
最理想的情况下, 找到一个最小的时间, 保证 "确认应答一定能在这个时间内返回". 但是这个时间的是非, 随着网络情况的差别, 是有差异的. 如果超时时间设的太长, 会影响整体的重传效率; 如果超时时间设的太短, 有大概会频仍发送重复的包 超时时间是动态的,取决于当前网络状态。例如:Linux的超时时间机制
Linux 中(BSD Unix 和 Windows 也是云云), 超时以 500ms 为一个单位进行控 制, 每次判断超时重发的超时时间都是 500ms 的整数倍. 如果重发一次之后, 仍然得不到应答, 等候 2*500ms 后再进行重传. 如果仍然得不到应答, 等候 4*500ms 进行重传. 依次类推, 以指数情势递增. 累计到一定的重传次数, TCP 以为网络或者对端主机出现异常, 强制关闭毗连 毗连受理机制:
在正常情况下 , TCP 要颠末三次握手建立毗连 , 四次挥手断开毗连 三次握手的目标是建立毗连: 第一次握手:客户端向服务端发送包含SYN的TCP报文,客户端的状态变为SYN_SEND; 第二次握手:服务端收到SYN报文后,进入SYN_RCVD状态;同时发送包含SYN和ACK的报文给客户端,通知客户端已经接受报文,必要进行确认。 第三次握手:收到SYN和ACK的报文后,客户端先把状态变为ESTABLISHED,以为建立毗连成功;然后给服务端发送ACK报文,服务端收到该报文,会进入ESTABLISHED,以为建立毗连成功。
至此,双方毗连建立成功,可以发送数据了。
四次挥手的目标是断开毗连:
第一次挥手:自动断开方发送包含FIN(请求结束)的报文,然后进入FIN_WAIT_1状态;
第二次挥手:被动断开方收到FIN报文,然后发送一个ACK报文(应答同意断开毗连);然后进入CLOSE_WAIT状态;自动方接受到该报文,进入FIN_WAIT_2状态,此时自动方到被动方的毗连已经断开,不能发数据了(应答还可以)。
第三次挥手:在发送完成ACK报文后,被动断开方还可以继续完成业务数据的发送,待剩余数据发送完成后,或者CLOSE-WAIT(关闭等候)截止后,被动断开方发送FIN报文,进入LAST_ACK状态。
第四次挥手:自动方收到FIN报文,进入TIME_WAIT状态,等候超时后最终关闭毗连;然后给被动方发送ACK报文。被动方接受到该报文,断开毗连。
至此,双方毗连断开。
注:在发送报文的过程中,如果毗连异常或者收到的报文有问题;就会给对方发一个含有RST的报文。
RST:用于重置一个已经混乱的毗连,也可用于拒绝一个无效的数据段或者拒绝一个毗连请求。如果数据段被设置了RST位,说明报文发送方有问题发生。
在内核中的过程:
在三次握手中,客户端起首要有套接字,服务端要处于监听状态;客户端通过connect()接口发起三次握手,如果建立毗连成功,服务端通过accept()返回新的套接字和客户端通信。
在四次握手中,自动方通过关闭套接字close(),发起四次挥手,期间被动发的read()接口阻塞,等候大概还要发送的数据,read()返回0,被动方也通过关闭套接字close(),继续四次挥手让毗连断开。
为什么是三次挥手?
1.保证信道(网络)是康健的。三次握手,双方都进行了一次发送和接受,保证双方都是全双工。
其次,1,2次握手,有安全隐患;服务器要维护毗连,必要本钱;选择1,2次握手,服务器大概被故意大量访问,使得服务器无法正常工作。
2.确保双方是康健且愿意通信的。三次握手,双方都有接受和请求,表示双方都愿意进行通信,制止不肯意的毗连。
四次挥手中的CLOSE_WAIT和TIME_WAIT:
1.CLOSE_WAIT:等候被动方内核调用close()关闭套接字;
对于服务器上出现大量的 CLOSE_WAIT 状态, 缘故原由就是服务器没有正确的关闭 socket, 导致四次挥手没有正确完成. 这是一个 BUG. 只必要加上对应的 close 即可解决问题。
2.TIME_WAIT:让客户到服务端的毗连等候,不消调用close();主要是保证第四次挥手,如果ACK报文没发到,对方会触发超时重传再来第四次挥手;其次为了比及历史陈旧报文抛弃以免对下次毗连产生影响。
TIME_WAIT期间,没有调用close(),相应的套接字是被占用的,下次绑定这个套接字会失败!
通常使用socketopt函数解决这个问题。
5.16位窗口大小
窗口大小指的是本身 接受缓冲区 的剩余空间大小;此字段用来进行流量控制。
6.流量控制
接收端处理数据的速度是有限的. 如果发送端发的太快, 导致接收端的缓冲区被打满, 这 个时间如果发送端继续发送, 就会造成丢包, 继而引起丢包重传等等一系列连锁反应. 因此 TCP 支持根据接收端的处理本领, 来决定发送端的发送速度. 这个机制就叫做流量 控制。 例: 接收端将本身可以接收的缓冲区大小放入 TCP 首部中的 "窗口大小" 字段, 通 过 ACK 端通知发送端; 窗口大小字段越大, 说明网络的吞吐量越高; 接收端一旦发现本身的缓冲区快满了, 就会将窗口大小设置成一个更小的值通 知给发送端; 发送端接受到这个窗口之后, 就会减慢本身的发送速度; 如果接收端缓冲区满了, 就会将窗口置为 0; 这时发送方不再发送数据, 但是需 要定期发送一个窗口探测数据段, 使接收端把窗口大小告诉发送端。 注:
如果接受端将窗口大小设置为0,发送方的探测报文会包含PSH控制标记,“催"对方赶紧把数据交给上层。
PSH:接收方在收到数据后立即将数据交给上层,而不是直到整个缓冲区满。
7.滑动窗口
滑动窗口,意思是临时不必要应答,可以一直发送数据。数据量也就是窗口大小是对方接受缓冲区的剩余大小(临时,不思量网络的状态)。
1.滑动窗口的动作
滑动窗口内的数据发送后,只有收到应答,窗谈锋会滑动。可以支持超时重传!
滑动窗口只能向右滑动,窗口左边的数据是已经被接受的。
滑动窗口的大小可以变大变小。窗口本质是一个限定区域,通过两个下标就可以维护。
2.滑动窗口的策略
只有收到应答的数据,才会被滑出窗口,来到窗口的左边;
如果窗口内发送的数据丢包,由于确认序号:只能确认序号之前的数据被接受。所有回应滑动窗口的应答都会只表示未收到的数据之前的序号(比如发送数据1000~5000,其中1001到2001的数据丢失,所有应答的确认序号都是1001)。
如果连续收到三个重复的确认序号,就会触发快重传机制:补发重复确认序号的报文。
如果数据发送的次数少(数据是一批一批发的),ACK也少,导致有丢失但是收到的重复确认序号少于三个,就触发超时重传机制!。
8.拥塞控制
固然 TCP 有了滑动窗口 , 能够高效可靠的发送大量的数据 . 但是如果在刚开 始阶段就发送大量的数据 , 仍然大概引发问题 . 因为网络上有很多的盘算机 , 大概当前的网络状态就已经比较拥堵 . 在不清晰当前网络 状态下 , 贸然发送大量的数据 , 只会更加堵塞。 TCP 引入 慢启动 机制 , 先发少量的数据 , 探探路 , 摸清当前的网络拥堵状态 , 再决定按 照多大的速度传输数据。
此处引入一个概念称为拥塞窗口
发送开始的时间, 定义拥塞窗口大小为 1;
每次收到一个 ACK 应答, 拥塞窗口加 1;
每次发送数据包的时间, 将拥塞窗口和接收端主机反馈的窗口大小做比较, 取较小的值作为实际发送的窗口;
像上面如许的拥塞窗口增长速度, 是指数级别的. "慢启动" 只是指初使时慢, 但是增长速
度非常快.为了不增长的那么快, 因此不能使拥塞窗口单纯的更加.此处引入一个叫做慢启动的阈值
当拥塞窗口凌驾这个阈值的时间, 不再按照指数方式增长, 而是按照线性方式增长
当 TCP 开始启动的时间 , 慢启动阈值等于窗口最大值 ; 在每次超时重发的时间 , 慢启动阈值会变成原来的一半 , 同时拥塞窗口置回 1; 少量的丢包 , 我们仅仅是触发超时重传 ; 大量的丢包 , 我们就以为网络拥塞 ; 当 TCP 通信开始后 , 网络吞吐量会逐渐上升 ; 随着网络发生拥堵 , 吞吐量会立即下降 ; 拥塞控制 , 归根结底是 TCP 协议想尽大概快的把数据传输给对方 , 但是又要制止给网络 造成太大压力的折中方案 .
9.TCP 异常情况 历程停止: 历程停止会开释文件描述符, 仍然可以发送 FIN. 和正常关闭没有什么区别. 呆板重启: 和历程停止的情况雷同. 呆板掉电/网线断开: 接收端以为毗连还在, 一旦接收端有写入操作, 接收端发现毗连已 经不在了, 就会进行 reset. 即使没有写入操作, TCP 本身也内置了一个保活定时器, 会 定期询问对方是否还在. 如果对方不在, 也会把毗连开释. 最后TCP为什么这么复杂? 因为要保证可靠性, 同时又尽大概的提高性能 。 感谢欣赏!!!
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |