TCP简介
- 面向连接的、可靠的、基于字节流的传输层通信协议
- 将应用层的数据流分割成报文段并发送给目标节点的TCP层
- 数据包都有序号,对方收到则发送ACK确认,未收到则重传
- 使用校验和来检验数据在传输过程中是否有误
TCP报文头
TCP报文头长度一般为20字节。主要有以下几部分:
- 源端口、目标端口
- Sequence number(seq)(4字节)
- Acknowledgement Number(ack)(4字节)
- 数据偏移
- 保留域
- 控制位(URG/ACK/PSH/RST/SYN/FIN)
- ACK:确认序号标志
- SYN:同步序号,用于建立连接过程
- FIN:finish标志,用于释放连接
- Window窗口:滑动窗口大小,告知发送端接收端的缓存大小,控制发送端发送速率,达到流量控制的目的
- Checksum:检验和(奇偶校验)
- 紧急指针
- 可选项
TCP和UDP的区别
(1)TCP面向连接;UDP面向无连接
(2)TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证;
(3)TCP传输速度慢;UDP速度快
(4)每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
(5)TCP对系统资源要求较多,UDP对系统资源要求较少。
(6)TCP的逻辑通信信道是全双工的可靠信道,UDP是不可靠信道。
(7)UDP没有拥塞机制,因此网络出现拥塞不会使源主机的发送速率降低。
(8)TCP首部开销20字节;UDP的首部开销小,只有8个字节。
- 什么时候应该使用TCP: 当对网络通讯质量有要求的时候,比如:整个数据要准确无误的传递给对方,这往往用于一些要求可靠的应用,比如HTTP、HTTPS、FTP等传输文件的协议,POP、SMTP等邮件传输的协议。 在日常生活中,常见使用TCP协议的应用如下: 浏览器,用的HTTP; FlashFXP,用的FTP; Outlook,用的POP、SMTP; Putty,用的Telnet、SSH; QQ文件传输 …
- 什么时候应该使用UDP: 当对网络通讯质量要求不高的时候,要求网络通讯速度能尽量的快,这时就可以使用UDP。 比如,日常生活中,常见使用UDP协议的应用如下: 实时语音、QQ视频…
有些应用场景对可靠性要求不高而对流量要求高时会用到UDP,比如流式多媒体通信、IP电话等
如图:
TCP三次握手四次挥手
建立连接协议(三次握手)
(1)客户端发送一个带SYN标志位、seq的TCP报文到server。这是三次握手过程中的报文1。此时client进入SYN_SEND 状态。
(2) server端回应client的报文,是三次握手中的第2个报文。这个报文同时带ACK(确认字符)标志、SYN标志、ack(=收到来自客户端的seq+1)、seq(server自己的)。因此它表示对刚才client SYN报文的回应。此时server进入SYN_RECV 状态。
(3) 客户必须再次回应服务段一个包括ACK、ack(=来自server的seq+1)、seq(第一次握手的seq+1)的报文,这是报文段3。此时双方进入ESTABLISHED 状态。
名词解释:
-
序列号seq:占4个字节,用来标记数据段的顺序,TCP把连接中发送的所有数据字节都编上一个序号,第一个字节的编号由本地随机产生;给字节编上序号后,就给每一个报文段指派一个序号;序列号seq就是这个报文段中的第一个字节的数据编号。
-
确认号ack:占4个字节,期待收到对方下一个报文段的第一个数据字节的序号;序列号表示报文段携带数据的第一个字节的编号;而确认号指的是期望接收到下一个字节的编号;因此当前报文段最后一个字节的编号+1即为确认号。
-
SYN:属于一个标志位,为1时代表这是一个连接请求(当ACK=0)或连接接受响应(当ACK=1)报文;SYN这个标志位只有在TCP建立连接时才会被置1,握手完成后SYN标志位被置0。
-
ACK:只在响应中出现。占1位,仅当ACK=1时,ack才有效。ACK=0时,ack无效。
连接终止协议(四次挥手)
因为TCP连接是全双工的,因此每一个方向都必须单独进行关闭。这原则是当一方完毕它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个FIN仅仅意味着这一方向上没有数据流动。一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将运行主动关闭。而还有一方运行被动关闭。
流程:
(1) 主机1发送FIN和seq。请求关闭主机1到主机2的数据传送(报文段4)。此时状态变化: 1:FIN_WAIT1
(2) 主机2收到这个FIN。它发回一个ACK、ack(收到的seq加1)、seq(报文段5)。
这一步代表主机2同意关闭连接,但连接并没有关闭,因为主机2可能还有数据没发完,为此需要等待。此时状态变化:2:CLOSE_WAIT | 1:FIN_WAIT2
(3) 主机2发完剩余数据,准备关闭与主机1的连接,并发送一个FIN给主机1(报文段6)。进入LAST-ACK(最后确认)状态。如果没收到主机1的回复,会进行超时重传的。
(4) 主机1收到主机2回复,知道它的数据发送完了。于是发回ACK报文确认收到,告诉主机2你可以关了。并将ack设置为收到序号加1(报文段7)。这样一来主机2收到后就安心关闭连接了。此时状态变化: 1:TIME_WAIT | 2:CLOSED。
这样四次挥手就完成了。不过别忘了,主机1还在TIME_WAIT状态,必须等待2MSL的时间才进入CLOSED状态,才能开始建立下一个新的连接,这个时间由时间等待计时器来实现。如果在这段时间又收到来自主机2的FIN+ACK报文(报文段6),就会再发送ACK报文回去,直至过了2MSL且再无回音,就关掉。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指任何IP数据报能够在因特网上存活的最长时间,2MSL就是一个发送和一个回复所需的最大时间。
除了时间等待计时器外,TCP还设有一个保活计时器。这是为了预防有这样的情况:客户端已主动与服务端建立了TCP连接,但是中途客户端挂掉了,导致服务端无法再接收到客户端的数据。因此应当有相应措施使得服务端不要一直等待。于是就有了保活计时器。每一次接收到客户端的数据,就会重新设置保活计时器,时间设置通常是2小时。若2小时没有收到客户端的数据,就会发送一个探测报文段,以后每隔75秒发送一次。若一连发送了10个探测报文段客户端仍然没有响应,服务器端就会关闭这个连接。
名词解释:
- FIN:用来释放一个连接。FIN=1表示:此报文段的发送方的数据已经发送完毕,并要求释放运输连接
3. 一些常见的问题
- 为什么要进行time wait,为什么要等2MSL?
为了保证A发送的最后一个ACK报文能够到达B。这个ACK报文段有可能丢失,因而使处在LAST-ACK状态的B收不到对已发送的FIN+ACK报文段的确认。没收到确认的话,B是会超时重传这个FIN+ACK报文段的,而A就能在2MSL时间内收到这个重传的FIN+ACK报文段。如果A在TIME-WAIT状态不等待一段时间,而是在发送完ACK报文段后就立即释放连接,就无法收到B重传的FIN+ACK报文段,因而也不会再发送一次确认报文段。这样,B就无法按照正常的步骤进入CLOSED状态。 - 为什么连接的时候是三次握手,关闭的时候却是四次握手?
因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,可能还有数据要传,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,是不能一起发送的。故需要四步挥手。 - 为什么要三次握手?
因为握手是为了确认双方收发功能均正常,进而确认可以同步序列号。第一次client -> server,server可以确认client发是好的;第二次server -> client,client可以确认自己收发是好的,对方收发也是好的;第三次client -> server,server可以确认自己收发是好的,对方也是。
为什么可以这么确认?是因为这收发之间都存在着校验。第一次server收到client的连接请求,若同意连接,就发送确认号,返回client要求的ack(收到的seq+1),并且也为自己选了一个初始序号seq;第三次client收到并返回的过程类似第二步。如此,就完成了对接。
专业点说就是为了初始化sequence num的初始值。为了实现可靠数据传输, TCP 协议的通信双方, 都必须维护一个序列号, 以标识发送出去的数据包中, 哪些是已经被对方收到的。 三次握手的过程即是通信双方相互告知序列号起始值, 并确认对方已经收到了序列号起始值的必经步骤。
如果只是两次握手, 至多只有连接发起方的起始序列号能被确认, 另一方选择的序列号则得不到确认。 - 首次握手的隐患 – SYN超时
当首次握手后发送给接收端的SYN包始终没有回应时,发送端会进行等待和再发送,再发送次数为5,次,每次间隔为1s、2s、4s、8s、32s,共63s。若是仍然没有回应,就断掉。这也导致了SYN Flood攻击。为了防御这种攻击,可以采取启用syncookie的方式。详情:https://blog.csdn.net/daodan988/article/details/51455007
TCP滑动窗口
详细介绍写在另一篇:传送门
RTT和RTO
- RTT:发送一个数据包到收到对应的ACK,所花费的时间
- RTO:重传时间间隔
TCP使用滑动窗口做流量控制和乱序重排
- 保证TCP的可靠性
- 保证TCP的流控特性
所谓流量控制,主要是接收方传递信息给发送方,使其不要发送数据太快,是一种端到端的控制。主要的方式就是返回的ACK中会包含自己的接收窗口的大小,并且利用大小来控制发送方的数据发送
。
这里面涉及到一种情况,如果B已经告诉A自己的缓冲区已满,于是A停止发送数据;等待一段时间后,B的缓冲区出现了富余,于是给A发送报文告诉A我的rwnd大小为400,但是这个报文不幸丢失了,于是就出现A等待B的通知||B等待A发送数据的死锁状态。为了处理这种问题,TCP引入了持续计时器(Persistence timer),当A收到对方的零窗口通知时,就启用该计时器,时间到则发送一个1字节的探测报文,对方会在此时回应自身的接收窗口大小,如果结果仍为0,则重设持续计时器,继续等待。
发送窗口相关概念
已发送并收到确认的数据(不在发送窗口和发送缓冲区之内)、已发送但未收到确认的数据(位于发送窗口之中)、允许发送但尚未发送的数据以及发送窗口外发送缓冲区内暂时不允许发送的数据;