TCP协议详解

TCP全称为 "传输控制协议(Transmission Control Protocol)",要对传输进行一个详细的控制。

TCP协议头格式

● 16位源/目的端口号:表示数据从哪个进程来,要到哪个进程去;

● 32位序号:用于保证报文的有序;

● 32位确认序号:用于对收到的报文进行确认;

● 4位首部长度:范围:0 - 15,单位:4字节,也就是说,用4位首部长度表示的数字,再乘上4字节,就代表该报文TCP报头的长度。

● 保留(6位);

● 6位标志位:用来区分报文的类型;

   URG:紧急指针是否有效,搭配16位紧急指针使用

   ACK:确认号是否有效

   PSH:提示接受端应用程序立刻从TCP接收缓冲区把数据读走

   RST:对方要求重新建立连接;我们把携带RST标识的称为复位报文段

   SYN:请求建立连接;我们把携带SYN标识的称为同步报文段

   FIN:通知对方,本端要关闭了;我们把携带FIN标识的称为结束报文段

● 16位窗口大小:接收端可以接收的缓冲区大小;

● 16位检验和:发送端填充,CRC校验.。接收端校验不通过,则认为数据有问题。此处的检验和不光包含TCP首部,也包含TCP数据部分;

● 16位紧急指针:由于TCP报文按需达到,每一个报文,什么时候被上层读取到基本是确定的。如果想让一个数据尽快的被上层读到,可以设置URG,表明该报文携带了紧急数据,需要被优先处理,而16位紧急指针则指向了需要被优先处理数据的位置。

如何分离

对于收到的TCP报文,由于4位首部长度的位置是固定的,可以优先读取4位首部长度,然后再将得到的数字乘以4,就得到了报头所对应的字节数,这样就可以将报头与有效载荷分离。

如何交付

● TCP协议位于传输层,当数据被TCP拿到后,此时的目的是将数据交付给上层对应的应用程序;

● 而不同的网络应用程序都对应了一个唯一的端口;

● 此时,可以通过报头中 16位目的端口号 字段,交付给应用层对应的应用程序;

TCP连接管理机制

在正常情况下,TCP要经过三次握手建立连接,四次挥手断开连接

三次握手

三次握手的过程

● 第一次握手:建立连接时,客户端向服务器发送SYN包,请求建立连接,等待确认;

● 第二次握手:服务端收到客户端的SYN包,回一个ACK+SYN包,告诉客户端已经收到,并向客户端请求建立连接,等待确认;

● 第三次握手:客户端收到ACK+SYN包,再回一个ACK包,告诉服务端已经收到;

为什么要三次握手

● 协商双方的初始序号与确认序号;

● 交换TCP窗口大小;

三次握手的本质是通信双方确认自已既能向对方发送数据,又能接收到对方发来数据的最少次数,如果只进行两次握手,至多只有连接发起方能确认自己同时具备上述两个能力,而另一方则不能。

四次挥手

四次挥手的过程

以客户端先断开连接为例。

● 第一次挥手:客户端发送FIN包给服务端,告诉服务端自己的数据已经发送完毕,请求终止连接,此时客户端不发送数据,但还能接收数据;

● 第二次挥手:服务端收到FIN包,回一个ACK包给客户端,告诉客户端已经收到FIN包,此时还没有断开socket连接,而是等待剩下的数据传输完毕‘

● 第三次挥手:服务端等待数据传输完毕后,向客户端发送FIN包,表明可以断开连接;

● 第四次挥手:客户端收到FIN包后,回一个ACK包表明确认收到,等待一段时间,确保服务端不再有数据发送过来,然后彻底断开连接;

服务端状态变化

[CLOSED -> LISTEN] 服务器端调用listen后进入LISTEN状态,等待客户端连接;

[LISTEN -> SYN_RCVD] 一旦监听到连接请求(同步报文段),就将该连接放入内核半连接队列中,并向客户端发送SYN确认报文;

[SYN_RCVD -> ESTABLISHED] 服务端一旦收到客户端的确认报文,就进入ESTABLISHED状态,并将该连接放入内核全连接队列中,通过accept从全连接队列中获取连接,然后可以进行读写数据了;

[ESTABLISHED -> CLOSE_WAIT] 当客户端主动关闭连接(调用close),服务器会收到结束报文段,服务器返回确认报文段并进入CLOSE_WAIT;

[CLOSE_WAIT -> LAST_ACK] 进入CLOSE_WAIT后说明服务器准备关闭连接(需要处理完之前的数据);当服务器真正调用close关闭连接时,会向客户端发送FIN,此时服务器进LAST_ACK状态,等待最后一个ACK到来(这个ACK是客户端确认收到了FIN);

[LAST_ACK -> CLOSED] 服务器收到了对FIN的ACK,彻底关闭连接;

客户端状态变化

[CLOSED -> SYN_SENT] 客户端调用connect,发送同步报文段;

[SYN_SENT -> ESTABLISHED] connect调用成功,则进入ESTABLISHED状态,开始读写数据;

[ESTABLISHED -> FIN_WAIT_1] 客户端主动调用close时,向服务器发送结束报文段,同时进入FIN_WAIT_1;

[FIN_WAIT_1 -> FIN_WAIT_2] 客户端收到服务器对结束报文段的确认,则进入FIN_WAIT_2,开始等服务器的结束报文段;

[FIN_WAIT_2 -> TIME_WAIT] 客户端收到服务器发来的结束报文段,进入TIME_WAIT,并发出LAST_ACK;

[TIME_WAIT -> CLOSED] 客户端要等待一个2MSL(Max Segment Life,报文最大生存时间)的时间,才会进入CLOSED状态;

TIME_WAIT状态

TCP协议规定,主动关闭连接的一方要处于TIME_WAIT状态,等待两个MSL(Maxmum Segment Lifetime)的时间后才能回到CLOSED状态;

在TIME_WAIT期间,定义这个连接的插口口(客户的IP地址和端口号,服务器的IP地址和端口号)不能再被使用,这个连接只能在2MSL结束后才能再被使用;

为什么需要有这个状态?

理论上四个报文都发送完毕,就可以直接进入CLOSED状态,但可能网络是不可靠的,有可能最后一个ACK丢失,导致对端不能正常关闭连接;也有可能在网络中还存在未被接收或迟到的数据,被下一个新到来的连接所获取。所以TIME_WAIT状态是用来重发可能丢失的ACK报文和让网络中残留的数据消散。

什么是MSL?

● MSL是Maxmum Segment Lifetime的英文缩写,可译为“最长报文段寿命”,它是任何报文在网络上存在的最长时间,超过这个时间,报文将被丢弃;

● 这个时间是有限的,因为TCP报文段是以IP数据报在网络内传输,而IP数据报有限制其生存时间的TTL字段;

● MSL在RFC1122中规定为两分钟,但是各操作系统的实现不同,在Centos7上默认配置的值是60s;

● 可通过cat /proc/sys/net/ipv4/tcp_fin_timeout查看MSL的值;

为什么TIME_WAIT的时间是2MSL?

● 保证两个传输方向上的尚未被接收或迟到的报文段都已经消失(否则服务器立即重启,可能会收到来自上一个进程的迟到的数据,但是这种数据很可能是错误的);

● 同时也是理论上保证最后一个ACK报文可靠传达(假设最后一个ACK丢失,那么服务器会重发一个FIN,这是虽然客户端的进程不在了,但是TCP连接还在,仍然可以重发LAST_ACK);

解决TIME_WAIT状态引起的bind失败的方法

在服务端的TCP连接没有完全断开之前不允许重新监听,某些情况下可能是不合理的。

● 服务器需要处理非常大量的客户端的连接,每个连接的生存时间可能很短,但是每秒都有很大数量的客户端来请求;

● 由于服务器的负载能力是有限的,对于占用服务端连接资源而不活跃的客户端,就需要被服务端主动清理,就会产生大量TIME_WAIT连接;

● 而在TIME_WAIT状态时的地址和端口还是被占用着的,所有会bind失败;

解决方法:借用setsockopt函数

#include <sys/types.h>
#include <sys/socket.h>
​
int setsockopt(int sockfd, int level, int optname, const void* optval, socklen_t optlen);

在第三个参数上设置SO_REUSEADDR选项。


在server代码的 socket() 和 bind() 调用之间插入如下代码:

int opt = 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

SO_REUSEADDR允许启动一个监听服务器并捆绑其众所周知端口,即使以前建立的将该端口用作它们的本地的连接仍存在。这个条件通常是这样碰到的:

(1) 启动一个监听服务器;

(2) 连接请求到达,派生一个子进程来处理这个客户;

(3) 监听服务器终止,但子进程继续为现有连接上的客户提供服务;

(4) 重启监听服务器;

默认情况下,当监听服务器在步骤(4)中通过调用socket、bind和listen重新启动时,由于它试图捆绑一个现有连接(即正由早先派生的那个子进程处理着的连接)上的端口,从而bind调用会失败。但如果该服务器在socket和bind中间调用设置了SO_REUSEADDR选项,那么bind将成功。

可靠性的保证

按序到达和去重

接收端对于收到的TCP数据包,会按序号对其重新排序以及去重。

确认应答

TCP将每个字节的数据都进行了编号,即为序列号。

对于到达的数据,接受端会返回一个带有ACK标识的报文,其中的32位确认序号是对历史报文的序号+1。

通过应答,来保证上一条信息被对方100%收到。TCP并不是100%可靠的,因为对于通信双方的最后一条数据是没有应答的。

超时重传

主机A发送数据给B之后,可能因为网络拥堵等原因,数据无法到达主机B;

如果主机A在一个特定时间间隔内,没有收到B发来的确认应答,就会进行重传;


但是,主机A未收到B发来的确认应答,也可能是因为ACK丢失了。

因此主机B会受到很多重复的数据,对于重复的数据,TCP能够根据序列号,对其进行去重。

超时时间

TCP为了保证无论在任何环境下都能比较高性能的通信,因此会动态计算这个最大超时时间。

● Linux中(BSD Unix和Windows也是如此), 超时以500ms为一个单位进行控制,每次判定超时重 发的超时时间都是500ms的整数倍。

● 如果重发一次之后,仍然得不到应答,等待 2 * 500ms 后再进行重传。

● 如果仍然得不到应答,等待 4 * 500ms 进行重传。依次类推,以指数形式递增。

● 累计到一定的重传次数,TCP认为网络或者对端主机出现异常,强制关闭连接。

最大消息长度

在建立TCP连接的时候,双方约定一个最大的长度(MSS)作为发送的单位,重传的时候也是以这个单位来进行的。理想的情况下是该长度的数据刚好不被网络层分片。

滑动窗口

对每一个发送的数据段,都要给一个ACK确认应答。收到ACK后再发送下一个数据段,这样做有一个 比较大的缺点,就是性能较差,尤其是数据往返的时间较长的时候。

既然一发一收的方式性能较低,那么我们一次发送多条数据,就可以大大的提高性能,本质是将多个段的等待时间重叠在一起了。

● 窗口大小指的是无需等待确认应答而可以继续发送数据的最大值,上图的窗口大小就是4000个字节(四个字段);

● 发送前四个段的时候,不需要任何ACK,直接发送;

● 收到第一个ACK后,滑动窗口向后移动,继续发送第五个段的数据;

● 操作系统内核为了维护这个滑动窗口,需要开辟 发送缓冲区 来记录当前还有哪些数据没有应答。只有确认应答过的数据,才能从缓冲区删掉;

● 窗口越大,网络的吞吐量就越大;

丢包问题

情况一:数据包已经抵达,ACK丢了

这种情况下,部分ACK丢了并不要紧,因为可以通过后续的ACK进行确认。


情况二:数据包丢了(快重传)

● 当某一段报文段丢失之后,发送端会一直收到 1001 这样的ACK,就像是在提醒发送端“我想要 的是1001”一样;

● 如果发送端主机连续三次收到了同样一个“1001”这样的应答,就会将对应的数据 1001-2000 重 新发送;

● 这个时候接受端收到了 1001 之后,再次返回的ACK就是 7001 了,因为 2001-7000 的数据接受端之前就已经收到了,被放到了接收端操作系统内核的 接收缓冲区 中。

这种机制被称为“快重传”。

流量控制

流量控制发生在发送端跟接受端之间。

什么是流量控制

接受端处理数据的速度是有限的,如果发送端发得太快,导致接受端的缓冲区被打满,这个时候如果发送端继续发送数据,就会造成丢包,继而引起丢包重传等一系列连锁反应。

因此TCP支持根据接受端的处理能力,来决定发送端的发送速度。这个机制就叫做流量控制

流量控制如何实现

● TCP采用可变滑动窗口来实现流量控制。

● 接受端将自己可以接收的缓冲区大小放入 TCP 首部中的“窗口大小”字段,通过ACK通知发送端;

● 窗口大小字段越大,说明网络的吞吐量越大;

● 接受端一旦发现自己的缓冲区快满了,就会将窗口大小设置成一个更小的值通知给发送端;

● 发送端接收到这个窗口之后,就会减慢自己的发送速度;

● 如果接收缓冲区满了,就会将窗口置为0;这时发送方不再发送数据,但是需要定期发送一个窗口探测数据段,使接受端把窗口大小告诉发送端。

一个问题

16位的窗口大小字段能表示最大的数是65535,那么TCP窗口的最大值就是65535字节吗?

实际上,TCP首部40字节选项中还包含一个窗口扩大因子M,实际窗口大小是 窗口字段的值左移 M 位。

拥塞控制

拥塞控制主要处理的问题是,整个网络环境,网络特别差,特别容易丢包的情况。

虽然TCP有了滑动窗口,能够高效可靠的发送大量的数据,但是如果在刚开始阶段就发送大量的数据,仍可能引发问题。

因为网络上有很多的计算机,可能当前的网络状态就已经比较拥堵,在不清楚网络状态下,贸然发送大量的数据,是很有可能引起雪上加霜的。

TCP 引入 慢启动 机制,先发少量的数据,探探路,摸清当前的网络拥堵状态,再决定按照多大的速度传输数据。

慢启动

此处引入一个概念称为 拥塞窗口

● 发送开始的时候,定义拥塞窗口的大小为 1 ;

● 每次收到一个ACK应答,拥塞窗口的大小就加 1 ;

● 每次发送数据包的时候,将拥塞窗口大小和接受端主机反馈的窗口大小作比较,取较小的值作为实际发送的窗口;

向上面这样的拥塞窗口的增长速度,是指数级别的。慢启动只是指初始时慢,但是增长速度非常快。为了不增长的那么快,因此不能使拥塞窗口单纯的加倍。

此处引入一个叫做 慢启动阈值

● 当拥塞窗口超过这个阈值的时候,不再按照指数方式增长,而是按照线性方式增长;

● 当TCP开始启动的时候,慢启动阈值ssthresh的初始值设置为 16 ;

● 在每次超时重发的时候,慢启动阈值会变为超时时的拥塞窗口大小的一半,同时拥塞窗口被置回 1 ;

少量的丢包,我们仅仅是触发超时重传;大量的丢包,我们就认为网络拥塞;

当TCP通信开始后,网络吞吐量回逐渐上升;随着网络发生拥堵,吞吐量会立刻下降;

拥塞控制,归根结底是TCP协议想尽可能快的把数据传输给对方,但是又要避免给网络造成太大压力的折中方案。

效率的保证

上述的滑动窗口机制与快重传机制都使效率得到提高,除此之外,TCP还引入了延迟应答捎带应答来保证效率。

延迟应答

如果接收数据的主机立刻返回ACK应答,这时候返回的窗口可能比较小。

● 假设接受端缓冲区为1M,一次收到了500K的数据;如果立刻应答,返回的窗口就是500K;

● 但实际上可能处理端处理的速度很快,10ms之内就把500K的数据从缓冲区消费掉了;

● 在这种情况下,接收端处理还远没达到自己的极限,即使窗口再大一些,也能处理过来;

● 如果接收端稍微等一会再应答,比如等待200ms再应答,那么这个时候返回的窗口大小就是1M;

一定要记得,窗口越大,网络吞吐量就越大,效率就越高。我们的目标是再保证网络不拥塞的情况下尽量提高传输效率。

那么所有的包都可以延迟应答吗?也不是。

● 数量限制:每隔N个包就应答一次;

● 时间限制:超过最大延迟时间就应答一次;

具体的数量和超过时间,依操作系统不同也有差异;一般N取2,超过时间取200ms;

捎带应答

如果应答和数据分开发送,就会产生很多额外的数据包。

● 在很多情况下,通信的双方需要相互发送数据;

● 那么,ACK这个时候就可以搭顺风车,与发送端发送的数据包一起返回给接收端;

● 因此,TCP报头中的ACK标识,在大多数情况下都是被设置的;

● 这样,接收端在收到数据的同时,也能确定自己的历史数据被对方收到;

TCP异常断开连接

进程终止

进程终止会释放文件描述符,仍然可以发送FIN,接着正常进行四次挥手,和正常关闭没有区别。

机器断电/网线断开

TCP保活机制

保活时间tcp_keepalive_time中,即此时连接处于非活动状态,在此期间服务器每收到一次客户端的请求后都会重新复位计时器,通常设定为2小时。若2小时未收到客户端任何数据,则开启保活功能的一端(假设为服务端),将给客户端发送保活探测报文,如果服务端未收到响应,经过保活时间间隔tcp_keepalive_intvl(默认为75s)后,服务端继续发送保活探测报文,直到发送次数为保活探测数tcp_keepalive_probes(默认为9次)。若依旧没有收到回复,则客户端确认不可达,连接也将中断。

无数据传输

如果两端的 TCP 连接一直没有数据交互,达到了触发 TCP 保活机制的条件,那么正常的一段内核里的 TCP 协议栈就会发送探测报文。若探测报文发送累计到一定次数后仍没得到回复,则断开连接。

有数据传输

客户端主机宕机,又迅速重启

在客户端主机宕机后,服务端向客户端发送的报文会得不到任何的响应,在一定时长后,服务端就会触发超时重传机制,重传未得到响应的报文。

服务端重传报文的过程中,客户端主机重启完成后,客户端的内核就会接收重传的报文,然后根据报文的信息传递给对应的进程:

● 如果客户端主机上没有进程监听该 TCP 报文的目标端口号,那么客户端内核就会回复 RST 报文,重置该 TCP 连接;

● 如果客户端主机上有进程监听该 TCP 报文的目标端口号,由于客户端主机重启后,之前的 TCP 连接的数据结构已经丢失了,客户端内核里协议栈会发现找不到该 TCP 连接的 socket 结构体,于是就会回复 RST 报文,重置该 TCP 连接。

所以,只要有一方重启完成后,收到之前 TCP 连接的报文,都会回复 RST 报文,以断开连接。

客户端主机宕机,一直没有重启

这种情况,服务端超时重传报文的次数达到一定阈值后,内核就会判定出该 TCP 有问题,然后通过 Socket 接口告诉应用程序该 TCP 连接出问题了,一般就是 ETIMEOUT 状态码,然后断开连接。

粘包问题

什么是粘包?

● 粘包问题中的包,指的是应用层的数据包;

● 在TCP 的协议头中,没有如同UDP一样的“报文长度”这样的字段,但是有一个序号这样的字段;

● 站在传输层的角度,TCP报文是一个一个过来的,按照序号排好序放在缓冲区中;

● 站在应用层的角度,看到的只是一串连续的字节数据;

● 那么应用程序看到了这么一连串的字节数据,就不知道从哪个部分开始到哪个部分,是一个完整的应用层数据包;

如何解决粘包问题?

归根结底就是一句话,明确两个包之间的边界。

● 对于定长的包,保证每次都按固定大小读取即可;

● 对于变长的包,可以在包头的位置,约定一个包总长度的字段,从而就知道了包的结束位置;

● 还可以在包和包之间使用明确的分隔符;

Listen的第二个参数

Linux内核协议栈为一个 TCP 连接管理使用两个队列:

● 半连接队列,用来保存处于 SYN_SENT 和 SYN_RECV 状态的请求;

● 全连接队列,用来保存处于 ESTABLISHED 状态,但是应用层没有调用accept取走的请求;

而全连接队列的长度会受到 listen 第二个参数的影响;

全连接队列满了的时候,就无法继续让当前连接的状态进入 ESTABLISHED 状态了;

全连接队列的长度是 listen 的第二个参数 + 1;

SYN洪水

● Linux内核会为 TCP 连接维护一个半连接队列;

● 当恶意分子在很短一段时间内,向服务端发送大量的 SYN 请求,服务端则会为这些请求建立数据结构,放入半连接队列中,并返回SYN+ACK包;

● 若这些恶意请求的发起方发送SYN请求后退出,服务端则会因为定时收不到回应而超时重发SYN+ACK包,在此期间,半连接队列会被一直占用;

● 而半连接队列的长度是有限的,当半连接队列被恶意请求占满时,后续到来的正常请求则会被服务端丢弃;

● 不仅消耗了服务器的 CPU 和内存资源,还会使后续正常请求失败;

如何减轻SYN洪水攻击

1、过滤网关防护

这里,过滤网关主要指明防火墙,当然路由器也能成为过滤网关。防火墙部署在不同网络之间,防范外来非法攻击和防止保密信息外泄,它处于客户端和服务器之间,利用它来防护SYN攻击能起到很好的效果。过滤网关防护主要包括超时设置,SYN网关和SYN代理三种。

● 网关超时设置

防火墙设置SYN转发超时参数(状态检测的防火墙可在状态表里面设置),该参数远小于服务器的timeout时间。当客户端发送完SYN包,服务端发送确认包后(SYN+ACK),防火墙如果在计数器到期时还未收到客户端的确认包(ACK),则往服务器发送RST包,以使服务器从队列中删去该半连接。值得注意的是,网关超时参数设置不宜过小也不宜过大,超时参数设置过小会影响正常的通讯,设置太大,又会影响防范SYN攻击的效果,必须根据所处的网络应用环境来设置此参数。

● SYN网关(将一部分半连接的数量转移到完全连接上了)

SYN网关收到客户端的SYN包时,直接转发给服务器;SYN网关收到服务器的SYN/ACK包后,将该包转发给客户端,同时以客户端的名义给服务器发ACK确认包。此时服务器由半连接状态进入连接状态。当客户端确认包到达时,如果有数据则转发,否则丢弃。事实上,服务器除了维持半连接队列外,还要有一个连接队列,如果发生SYN攻击时,将使连接队列数目增加,但一般服务器所能承受的连接数量比半连接数量大得多,所以这种方法能有效地减轻对服务器的攻击。

● SYN代理

当客户端SYN包到达过滤网关时,SYN代理并不转发SYN包,而是以服务器的名义主动回复SYN/ACK包给客户,如果收到客户的ACK包,表明这是正常的访问,此时防火墙向服务器发送ACK包并完成三次握手。SYN代理事实上代替了服务器去处理SYN攻击,此时要求过滤网关自身具有很强的防范SYN攻击能力。

2、加固tcp/ip协议栈

防范SYN攻击的另一项主要技术是调整tcp/ip协议栈,修改tcp协议实现。主要方法SYN cookies技术、增加最大半连接和缩短超时时间等。tcp/ip协议栈的调整可能会引起某些功能的受限,管理员应该在进行充分了解和测试的前提下进行此项工作。

● 增加积压队列(增加最大半连接数)

目标设备上的每个操作系统都具有一定数量的半开放连接。对大量SYN数据包的一个响应是增加OS允许的可能半开连接的最大数量。为了成功增加最大积压,系统必须预留额外的内存资源来处理所有新的请求。如果系统没有足够的内存来处理增加的积压队列大小,系统性能将受到负面影响,但仍然可能优于拒绝服务。

● 回收最早的半开TCP连接

一旦积压已被填补,另一个缓解策略就是覆盖最早的半开式连接。这种策略要求合法连接可以在比积压时间(恶意填充恶意SYN数据包的)更短的时间内建立连接。当攻击量增加时,或者如果积压量太小而不实际,这种特定的防御就会失败。

● SYN cookie

我们知道,TCP协议开辟了一个比较大的内存空间backlog队列来存储半连接条目,当SYN请求不断增加,并这个空间,致使系统丢弃SYN连接。为使半连接队列被塞满的情况下,服务器仍能处理新到的SYN请求,SYN cookies技术被设计出来。

SYN cookies应用于linux、FreeBSD等操作系统,当半连接队列满时,SYNcookies并不丢弃SYN请求,而是通过加密技术来标识半连接状态。

在TCP实现中,当收到客户端的SYN请求时,服务器需要回复SYN+ACK包给客户端,客户端也要发送确认包给服务器。通常,服务器的初始序列号由服务器按照一定的规律计算得到或采用随机数,但在SYN cookies中,服务器的初始序列号是通过对客户端IP地址、客户端端囗、服务器IP地址和服务器端囗以及其他一些安全数值等要素进行hash运算,加密得到的,称之为cookie。

当服务器遭受SYN攻击使得backlog队列满时,服务器并不拒绝新的SYN请求,而是回复cookie(回复包的SYN序列号)给客户端, 如果收到客户端的ACK包,服务器将客户端的ACK序列号减去1得到cookie比较值,并将上述要素进行一次hash运算,看看是否等于此cookie。如果相等,则直接完成三次握手。

TCP和UDP的区别

连接与无连接、可靠性、有序性、数据边界、速度、发送消耗、报头大小、拥塞控制、流量控制......

应用

● 由于TCP提供可靠交付和有序性的保证,它是最适合需要高可靠并且对传输时间要求不高的应用;

● UDP更适合应用程序需要快速,高效的传输的应用,如游戏;

● UDP有无状态的性质,在服务端需要对大量客户端产生的少量请求进行应答时是非常有用的;

● 在实践中,TCP会被用于金融领域,而UDP是大量使用在游戏领域;

上层使用的协议

基于TCP协议的:Telnet,FTP以及SMTP协议等;

基于UDP协议的:DHCP,DNS等;

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

waywt1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值