发送端: 加上伪首部之后,二进制反码求和 在取反
接收端: 加上伪首部之后,二进制反码求和 在取反 结果为全 1 则代表无差错
TCP首部:
源端口和目的端口:各占2个字节,分别写入源端口和目的端口;
序号:占4字节, 在一个TCP连接中传送的字节流中的字节流中的每一个字节都按顺序编号,本字段表示本报文段所发送数据的第一个字节的序号
确认号:占4个字节, 期望收到对方下一个报文段得第一个数据字节的序号。若确认号为N,则证明到序号N-1之前的所有数据都以正确收到。
数据偏移: 即TCP首部偏移的长度,它指出TCP报文段的数据起始处距离TCP报文段的起始处有多远。占4位,以4B为单位即一个数值是4B
保留:占6位,保留为今后使用,但目前应置为0;
6个控制位:
窗口:指的是发送报文段的一方接收窗口,即现在允许对方发送的数据量。
检验和:检验首部+数据,检验时要加上12B伪首部,第四个字段为6
紧急指针:URG=1时才有意义,指出本报文段中紧急数据的字节数。
选项:最大报文段长度MSS、窗口扩大、时间戳、选择确认…
1. 连接
2. 服务对象
3. 可靠性
4. 拥塞控制、流量控制
5. 首部开销
20
个字节,如果使用了「选项」字段则会变长的。TCP 和 UDP 应用场景:
由于 TCP 是面向连接,能保证数据的可靠性交付,因此经常用于:
FTP
文件传输HTTP
/ HTTPS
由于 UDP 面向无连接,它可以随时发送数据,再加上UDP本身的处理既简单又高效,因此经常用于:
DNS
、SNMP
等(1)目的:三次握手就是为了建立可靠的通信信道,简单来说就是让客户端和服务端确认彼此的发送和接收能力是正常的。
(2)过程:
①第一次握手:客户端发送请求连接报文段,无应用层数据,报文段中同步位SYN=1(表明该报文是一个连接报文),初始化序列号seq=x(随机值)
服务端收到之后,就表明客户端 的发送能力是正常的,服务端的接收能力是正常的
②第二次握手:服务端收到连接报文后,为该TCP连接分配缓存和变量,并向客户端发送确认报文段。允许连接,此报文段无应用层数据。报文段中,同步位SYN=1,确认位ACK=1,确认号ack= x+1,服务端也会初始化一个序列号seq=y
客户端收到之后,就能确认,自己的接收和发送是正常的,服务端的发送和接收是正常的
③第三次握手:客户端为该TCP连接分配缓存和变量,并向服务器返回一个确认报文,可以携带数据。此报文段中,SYN=0,ACK=1,seq=x+1,ack=y+1
服务端收到之后,就能确认客户端的接收能力是正常的,自己的发送能力是正常的
最终结果:
至此,客户端和服务端确认了彼此的发送和接收能力都正常,这样客户端和服务端就完成三次握手建立TCP连接了!
为什么需要三次握手,不能两次握手吗?
接下来以三个方面分析三次握手的原因:
三次握手才可以阻止历史重复连接的初始化(主要原因)
客户端连续发送多次 SYN 建立连接的报文,在网络拥堵等情况下:
SYN + ACK
报文给客户端;RST
报文给服务端,表示中止这一次连接。如果是两次握手连接,就不能判断当前连接是否是历史连接,三次握手则可以在客户端(发送方)准备发送第三次报文时,客户端因有足够的上下文来判断当前连接是否是历史连接:
RST
报文,以此中止历史连接;ACK
报文,通信双方就会成功建立连接;所以, TCP 使用三次握手建立连接的最主要原因是防止历史连接初始化了连接。
三次握手才可以同步双方的初始序列号
序列号在 TCP 连接中占据着非常重要的作用:
接收方可以去除重复的数据;
接收方可以根据数据包的序列号按序接收;
可以标识发送出去的数据包中, 哪些是已经被对方收到的;
四次握手其实也能够可靠的同步双方的初始化序号,但由于第二步和第三步可以优化成一步,所以就成了「三次握手」。
而两次握手只保证了一方的初始序列号能被对方成功接收,没办法保证双方的初始序列号都能被确认接收。
三次握手才可以避免资源浪费
如果只有「两次握手」,当客户端的 SYN
请求连接在网络中阻塞,客户端没有接收到 ACK
报文,就会重新发送 SYN
,由于没有第三次握手,服务器不清楚客户端是否收到了自己发送的建立连接的 ACK
确认信号,所以每收到一个 SYN
就只能先主动建立一个连接,这会造成什么情况呢?
如果客户端的 SYN
阻塞了,重复发送多次 SYN
报文,那么服务器在收到请求后就会建立多个冗余的无效链接,造成不必要的资源浪费。
即两次握手会造成消息滞留情况下,服务器重复接受无用的连接请求 SYN
报文,而造成重复分配资源。
小结:
TCP 建立连接时,通过三次握手能防止历史连接的建立,能减少双方不必要的资源开销,能帮助双方同步初始化序 列号。序列号能够保证数据包不重复、不丢弃和按序传输。
不使用「两次握手」和「四次握手」的原因:
什么是SYN洪泛攻击?有什么解决策略?
服务器端的资源分配是在二次握手时分配的,而客户端的资源是在完成三次握手时分配的,所以服务器容易受到SYN洪泛攻击,SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server则回复确认包,并等待Client确认,由于源地址不存在,因此Server需要不断重发直至超时,这些伪造的SYN包将长时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络拥塞甚至系统瘫痪。
如果已经建立了连接,但是客户端突然出现故障了怎么办?
TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
过程:
(1)第一次挥手:主机1没有数据要向主机2发送了,主机1决定释放连接,就会向主机2发送一个终止连接报文,其中终止位FIN=1,seq=u,主机1进入 FIN-WAIT1(终止等待1)状态。
(2)第二次挥手:主机2收到主机1的终止连接报文后,就会发送一个确认报文,其中确认位ACK=1,确认号ack=u+1,seq=v,并进入CLOSE-WIAT(关闭等待)状态。但这时,连接并为完全释放,服务端会通知应用层释放主机1和主机2之间的连接。此时TCP处于半关闭状态。
主机1收到确认报文后就进入FIN-WAIT2(终止等待2)状态
(3)第三次挥手:主机2发送完所有数据后,也准备释放连接了,此时就会向主机1发送一个终止连接的报文,其中FIN=1,ACK=1,ack=u+1,seq=w ,然后主机2进入LAST-ACK(最后确认状态)
(4)第四次挥手:主机1收到主机2的终止连接报文后,还要进行一次确认,确认报文中ACK=1,ack=w+1,seq=u+1,然后主机1进入TIME-WAIT(时间等待)状态。主机2收到确认报文后,进入CLOSED(关闭)状态。主机1等待2MSL后,也进入CLOSED(关闭)状态。
为什么连接的时候是三次握手,关闭的时候却是四次握手?
四次挥手是为了确保数据能够完成传输,但关闭连接 时,当收到对方的 FIN 报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可以未必会马上会关闭 SOCKET, 也即你可能还需要发送一些数据给对方之后,再发送 FIN 报文给对方来表示你同意现在可以关闭连接了,所以它这里的 ACK 报文和 FIN 报文多数情况下都是分开发送的
为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。
还有一个原因,防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中不会出现旧连接的请求报文
TIME_WAIT 过多有什么危害?
如果服务器有处于 TIME-WAIT 状态的 TCP,则说明是由服务器方主动发起的断开请求。
过多的 TIME-WAIT 状态主要的危害有两种:
服务器出现了大量CLOSE_WAIT状态如何解决?
大量 CLOSE_WAIT 表示程序出现了问题,对方的 socket 已经关闭连接,而我方忙于读或写没有及时关闭连接,需要检查代码,特别是释放资源的代码,或者是处理请求的线程配置。
TIME_WAIT 和 CLOSE_WAIT 的区别?
TIME_WAIT 是主动关闭链接时形成的,等待2MSL时间,约4分钟。主要是防止最后一个ACK丢失。 由于TIME_WAIT 的时间会非常长,因此server端应尽量减少主动关闭连接
CLOSE_WAIT是被动关闭连接是形成的。根据TCP状态机,服务器端收到客户端发送的FIN,则按照TCP实现发送ACK,因此进入CLOSE_WAIT状态。但如果服务器端不执行close(),就不能由CLOSE_WAIT迁移到LAST_ACK,则系统中会存在很多CLOSE_WAIT状态的连接。此时,可能是系统忙于处理读、写操作,而未将已收到FIN的连接,进行close。此时,recv/read已收到FIN的连接socket,会返回0。
连接管理就是三次握手与四次挥手的过程,在前面详细讲过这个过程,这里不再赘述。保证可靠的连接,是保证可靠性的前提
自动重传请求(Automatic Repeat-reQuest,ARQ)是OSI模型中数据链路层和传输层的错误纠正协议之一。它通过使用确认和超时这两个机制,在不可靠服务的基础上实现可靠的信息传输。如果发送方在发送后一段时间之内没有收到确认帧,它通常会重新发送。ARQ包括停止等待ARQ协议和连续ARQ协议。
(1)停止等待ARQ协议
优点: 简单
缺点: 信道利用率低,等待时间长
(2)连续ARQ协议
连续 ARQ 协议可提高信道利用率。发送方维持一个发送窗口,凡位于发送窗口内的分组可以连续发送出去,而不需要等待对方确认。接收方一般采用累计确认,对按序到达的最后一个分组发送确认,表明到这个分组为止的所有分组都已经正确收到了。
优点: 信道利用率高,容易实现,即使确认丢失,也不必重传。
缺点: 不能向发送方反映出接收方已经正确收到的所有分组的信息。 比如:发送方发送了 5条 消息,中间第三条丢失(3号),这时接收方只能对前两个发送确认。发送方无法知道后三个分组的下落,而只好把后三个全部重传一次。这也叫 Go-Back-N(回退 N),表示需要退回来重传已经发送过的 N 个消息。
滑动窗口以字节为单位。发送端有一个发送窗口。窗口前边的是已发送并且被确认的分组,窗口后边是还没有轮到的分组。滑动窗口里面也分为两块,一块是已经发送但是未被确认的分组,另一块是窗口内等待发送的分组。随着已发送的分组不断被确认,窗口内等待发送的分组也会不断被发送。整个窗口就会往后移动,让还没轮到的分组进入窗口内。
滑动窗口起到了一个限流的作用,也就是说当前滑动窗口的大小决定了当前 TCP 发送包的速率,而滑动窗口的大小取决于拥塞控制窗口和流量控制窗口的两者间的最小值。
流量控制就是发送方根据接收方的接收能力来动态调整自己的发送速度以确保接收方能来得及接收数据。
在通信过程中,接收方根据接收缓存的大小来设置确认报文段中窗口字段的大小,发送方的发送窗口大小取决于接收窗口的大小和拥塞窗口的大小的最小值。
流量控制是通过滑动窗口机制实现的。
发送窗口不能超过接收方的接收窗口大小。在0窗口通知后发送方就暂停发送数据了。但是在0窗口通知后可能会出现死锁问题,例如:接收方的接收缓冲又有了一些存储空间,但该通知丢失了,发送方和接收方互相等待消息。。
TCP为每个连接设置一个持续计时器,只要TCP连接的一方收到零窗口通知了,就启动该持续计时器。
若持续计时器的时间到期了,就会发送一个零窗口探测报文段,接收方在接收到后就会返回最新的的窗口大小。如果仍然是0的话,就会重启该持续计时器。
当网络中对资源的需求超过了资源的可用量,导致网络性能变差,网络吞吐量随输入负荷的增大而下降时就表明出现了拥塞。
拥塞控制其实就是尽量减少注入网络的数据,减轻网络中的路由器和链路的负担。
为了进行拥塞控制,TCP 发送方要维持一个 拥塞窗口(cwnd) 的状态变量。拥塞控制窗口的大小取决于网络的拥塞程度,并且动态变化。发送方让自己的发送窗口取决定于拥塞窗口和接收方的接受窗口中较小的一个。
TCP的拥塞控制采用了四种算法,即 慢开始 、 拥塞避免 、快重传 和 快恢复。
流量控制和拥塞控制的区别:
流量控制是一个端到端的问题,
而拥塞控制是一个全局性问题,涉及到所有的主机、所有的路由器。