TCP可靠连接,网络连接和断开过程中三次握手、四次挥手。
TCP报文
报文为20字节固定长度+4字节*15 - 20 = 40字节,最大头部长度是60字节。
数据偏移单位是4字节。
建立连接–三次握手
问题1: 为什么需要三次连接,两次不可以吗?
- 为了防止已经失效的连接请求报文发送给服务端,从而产生错误。假设客户端发送连接请求,由于网络中不稳定情况滞留很久,这是客户端重新发送请求连接报文,客户端现接受了客户端第二次请求的报文建立连接后,又收到第一次客户端发送的连接请求报文,三次连接时,如果服务端重新接收到客户端发送的连接报文请求,会发送一个确认报文给客户端,客户端接收到确认报文后不做任何处理。如果是两次握手,客户端和服务端会再次建立连接,将会导致异常的错误和资源浪费。
问题2: 为什么三次握手,返回时,ack值seq加1(ack=x+1)
确认收到的序列,并且告诉发送端下一次发送的序列号从哪开始(便于接收方对数据进行排序,便于选择重传)。
问题3: SYN洪泛攻击(SYN Flood,半开放攻击),怎么解决?
什么是SYN洪泛攻击?
- SYN Flood利用TCP协议的缺陷,发送大量伪造的TCP连接请求,常用假冒的IP或IP号段发送海量的请求连接的第一个握手包(SYN包),被攻击服务器回应第二个握手包(SYN + ACK包),因为对方是假冒IP,对方永远收不到包且不会回应第三个握手包。导致被攻击服务器保持大量SYN_RCVD状态的“半连接”,并且会重试5次回应第二个握手包,大量随机的恶意syn占满未完成连接队列,导致正常合法的syn排不上队列,让正常的业务请求连接不进来。【服务器端的资源分配是在二次握手时分配的,而客户端的资源是在完成三次握手时分配的,所以服务器容易受到SYN洪泛攻击】
- 检测SYN攻击非常的方便,当你在服务器上看到大量的半连接状态时,特别是源IP地址是随机的,基本上可以断定这是一次SYN攻击【使用netstats命令查看】
怎么解决
- 缩短超时(SYN Timeout)时间
- 怎加最大半连接数
- 过滤网关防护
- SYN cookies技术
SYN cookies技术
- 当服务器接受到SYN报文时,不直接为该TCP分配资源,而只是打开一个半开的套接字。接着会使用SYN报文段的源IP,目的IP,端口号以及只有服务器自己知道的一个秘密函数生成一个cookie,并把cookie作为序列号相应给客户端。
- 如果客户端是正常连接,将会返回一个确认字段为cookie+1的报文段。接下来服务网器会根据确认报文的源IP,目的IP,端口号以及秘密函数计算出一个结果,如果结果的值+1等于确认字段的值,则证明是刚刚请求连接的客户端,这时候才为该TCP分配资源。
问题4: TCP三次握手中,最后一次回复丢失,会发生什么?
- 如果最后一次ACK在网络中丢失,那么服务器端该TCP连接的状态仍为SYN_RCVD,并且根据TCP的超时重传机制依次等待3s/6s/12s后重新发送SYN+ACK包,以便客户端重新发送ACK包
- 如果重传指定次数后,仍然未收到ACK应答,那么一段时间后,服务端自动关闭这个连接
- 但是客户端认为这个连接已经建立,如果客户端向服务端发送数据,服务端将以RST包(reset,标示复位,用于异常的关闭连接)响应,此时,客户端知道三次握手失败。
断开连接–四次挥手
问题5: 为什么连接的时候是三次握手,关闭的时候却是四次握手?
建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以服务器可以立即关闭,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接。因此,服务器ACK和FIN一般都会分开发送,从而导致多了一次。
问题6: 为什么TCP挥手每两次中间有一个 FIN-WAIT2等待时间?
主动关闭的一端调用完close以后(即发FIN给被动关闭的一端, 并且收到其对FIN的确认ACK)则进入FIN_WAIT_2状态。如果这个时候因为网络突然断掉、被动关闭的一段宕机等原因,导致主动关闭的一端不能收到被动关闭的一端发来的FIN(防止对端不发送关闭连接的FIN包给本端),这个时候就需要FIN_WAIT_2定时器, 如果在该定时器超时的时候,还是没收到被动关闭一端发来的FIN,那么直接释放这个链接,进入CLOSE状态
问题7: 为什么客户端最后还要等待2MSL?为什么还有个TIME-WAIT的时间等待?
- 保证客户端发送的最后一个ACK报文能够到达服务器,因为这个ACK报文可能丢失,服务器已经发送了FIN+ACK报文,请求断开,客户端却没有回应,于是服务器又会重新发送一次,而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,并且会重启2MSL计时器。防
- 类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失,这样新的连接中不会出现旧连接的请求报文。
- 2MSL,最大报文生存时间,一个MSL 30 秒,2MSL = 60s
问题8: 客户端 TIME-WAIT 状态过多会产生什么后果?怎样处理?
-
作为服务器,短时间内关闭了大量的Client连接,就会造成服务器上出现大量的TIME_WAIT连接,占据大量的tuple /tApl/ ,严重消耗着服务器的资源,此时部分客户端就会显示连接不上
-
作为客户端,短时间内大量的短连接,会大量消耗的Client机器的端口,毕竟端口只有65535个,端口被耗尽了,后续就无法在发起新的连接了
-
在高并发短连接的TCP服务器上,当服务器处理完请求后立刻主动正常关闭连接。这个场景下会出现大量socket处于TIME_WAIT状态。如果客户端的并发量持续很高,此时部分客户端就会显示连接不上高并发可以让服务器在短时间范围内同时占用大量端口,而端口有个0~65535的范围,并不是很多,刨除系统和其他服务要用的,剩下的就更少了
-
短连接表示“业务处理+传输数据的时间 远远小于 TIME_WAIT超时的时间”的连接
解决方法:用负载均衡来抗这些高并发的短请求;服务器可以设置 SO_REUSEADDR 套接字选项来避免 TIME_WAIT状态,TIME_WAIT 状态可以通过优化服务器参数得到解决,因为发生TIME_WAIT的情况是服务器自己可控的,要么就是对方连接的异常,要么就是自己没有迅速回收资源,总之不是由于自己程序错误导致的强制关闭,发送 RST 包越过TIMEWAIT状态,直接进入CLOSED状态
SO_REUSEADDR是让端口释放后立即就可以被再次使用。
问题9: 服务器出现了大量 CLOSE_WAIT 状态如何解决?
大量 CLOSE_WAIT 表示程序出现了问题,对方的 socket 已经关闭连接,而我方忙于读或写没有及时关闭连接,需要检查代码,特别是释放资源的代码,或者是处理请求的线程配置。
参考
https://www.zhihu.com/question/271701044/answer/1808988570