面试官,不要再问我三次握手和四次挥手

📅 2026/7/10 12:21:03
面试官,不要再问我三次握手和四次挥手
三次握手和四次挥手是各个公司常见的考点也具有一定的水平区分度也被一些面试官作为热身题。很多小伙伴说这个问题刚开始回答的挺好但是后面越回答越冒冷汗最后就歇菜了。见过比较典型的面试场景是这样的:面试官请介绍下三次握手求职者第一次握手就是客户端给服务器端发送一个报文第二次就是服务器收到报文之后会应答一个报文给客户端第三次握手就是客户端收到报文后再给服务器发送一个报文三次握手就成功了。面试官然后呢求职者这就是三次握手的过程很简单的。面试官。。。。。。番外篇一首凉凉送给你记住猿人谷一句话面试时越简单的问题一般就是隐藏着比较大的坑一般都是需要将问题扩展的。上面求职者的回答不对吗当然对但距离面试官的期望可能还有点距离。希望大家能带着如下问题进行阅读收获会更大。请画出三次握手和四次挥手的示意图为什么连接的时候是三次握手什么是半连接队列ISN(Initial Sequence Number)是固定的吗三次握手过程中可以携带数据吗如果第三次握手丢失了客户端服务端会如何处理SYN攻击是什么挥手为什么需要四次四次挥手释放连接时等待2MSL的意义?1. 三次握手三次握手Three-way Handshake其实就是指建立一个TCP连接时需要客户端和服务器总共发送3个包。进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备。实质上其实就是连接服务器指定端口建立TCP连接并同步连接双方的序列号和确认号交换TCP窗口大小信息。刚开始客户端处于 Closed 的状态服务端处于 Listen 状态。进行三次握手第一次握手客户端给服务端发一个 SYN 报文并指明客户端的初始化序列号 ISN。此时客户端处于SYN_SENT状态。首部的同步位SYN1初始序号seqxSYN1的报文段不能携带数据但要消耗掉一个序号。第二次握手服务器收到客户端的 SYN 报文之后会以自己的 SYN 报文作为应答并且也是指定了自己的初始化序列号 ISN(s)。同时会把客户端的 ISN 1 作为ACK 的值表示自己已经收到了客户端的 SYN此时服务器处于SYN_RCVD的状态。在确认报文段中SYN1ACK1确认号ackx1初始序号seqy。第三次握手客户端收到 SYN 报文之后会发送一个 ACK 报文当然也是一样把服务器的 ISN 1 作为 ACK 的值表示已经收到了服务端的 SYN 报文此时客户端处于ESTABLISHED状态。服务器收到 ACK 报文之后也处于ESTABLISHED状态此时双方已建立起了连接。确认报文段ACK1确认号acky1序号seqx1初始为seqx第二个报文段所以要1ACK报文段可以携带数据不携带数据则不消耗序号。发送第一个SYN的一端将执行主动打开active open接收这个SYN并发回下一个SYN的另一端执行被动打开passive open。在socket编程中客户端执行connect()时将触发三次握手。用更通俗的语言来解释三次握手过程服务端调用listen系统命令进入监听状态等待客户端的连接。客户端向服务端发送连接请求报文其中TCP标志位里SYN1ACK0选择一个初始的序号x。服务端收到请求报文向 客户端 发送连接确认报文SYN1ACK1确认号为 x1同时也选择一个初始的序号 y。客户端 收到 服务端的连接确认报文后还要向 服务端发出确认确认号为 y1序号为 x1。服务端 收到 客户端 的确认后连接建立。1.1 为什么需要三次握手两次不行吗第三次握手是为了防止失效的连接请求到达服务器让服务器错误打开连接。弄清这个问题我们需要先弄明白三次握手的目的是什么能不能只用两次握手来达到同样的目的。第一次握手客户端发送网络包服务端收到了。这样服务端就能得出结论客户端的发送能力、服务端的接收能力是正常的。第二次握手服务端发包客户端收到了。这样客户端就能得出结论服务端的接收、发送能力客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常。第三次握手客户端发包服务端收到了。这样服务端就能得出结论客户端的接收、发送能力正常服务器自己的发送、接收能力也正常。因此需要三次握手才能确认双方的接收与发送能力是否正常。试想如果是用两次握手则会出现下面这种情况如客户端发出连接请求但因连接请求报文丢失而未收到确认于是客户端再重传一次连接请求。后来收到了确认建立了连接。数据传输完毕后就释放了连接客户端共发出了两个连接请求报文段其中第一个丢失第二个到达了服务端但是第一个丢失的报文段只是在某些网络结点长时间滞留了延误到连接释放以后的某个时间才到达服务端此时服务端误认为客户端又发出一次新的连接请求于是就向客户端发出确认报文段同意建立连接不采用三次握手只要服务端发出确认就建立新的连接了此时客户端忽略服务端发来的确认也不发送数据则服务端一致等待客户端发送数据浪费资源。番外篇有老铁问了个问题有个小疑惑下面这里是不是写错了第二次握手服务端发包客户端收到了。这样客户端就能得出结论服务端的接收、发送能力客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常。第二次握手只能确认客户端的发送能力是正常的还不能确认客户端的接收能力吧第三次握手才能确认不太懂请指教。可以试着这样理解你先给女朋友表白对方回复你“我爱你”此时你们的恋人关系能确定吗此时只有你自己知道对方能接收你的表白而且也能回复你的表白相当于你自己知道服务端的接收、发送能力正常但服务端并不知道客户端的接收能力是否正常的此时人家女孩子是不知道你是否接收到了她的爱慕只是第一次你先表白女孩子知道你发送能力没毛病但不知道你能否接收别人的信息。第三次你回复“我们彼此相爱”大功告成牵手成功有情人终成眷属!1.2 什么是半连接队列服务器第一次收到客户端的 SYN 之后就会处于 SYN_RCVD 状态此时双方还没有完全建立其连接服务器会把此种状态下请求连接放在一个队列里我们把这种队列称之为半连接队列。当然还有一个全连接队列就是已经完成三次握手建立起连接的就会放在全连接队列中。如果队列满了就有可能会出现丢包现象。这里再补充一点关于SYN-ACK 重传次数的问题服务器发送完SYN-ACK包如果未收到客户确认包服务器进行首次重传等待一段时间仍未收到客户确认包进行第二次重传。如果重传次数超过系统规定的最大重传次数系统将该连接信息从半连接队列中删除。注意每次重传等待的时间不一定相同一般会是指数增长例如间隔时间为 1s2s4s8s…关于建连接时SYN超时。试想一下如果server端接到了clien发的SYN后回了SYN-ACK后client掉线了server端没有收到client回来的ACK那么这个连接处于一个中间状态即没成功也没失败。于是server端如果在一定时间内没有收到的TCP会重发SYN-ACK。在Linux下默认重试次数为5次重试的间隔时间从1s开始每次都翻售5次的重试时间间隔为1s, 2s, 4s, 8s, 16s总共31s第5次发出后还要等32s都知道第5次也超时了所以总共需要 1s 2s 4s 8s 16s 32s 2^6 -1 63sTCP才会把断开这个连接。1.3 ISN(Initial Sequence Number)是固定的吗当一端为建立连接而发送它的SYN时它为连接选择一个初始序号。ISN随时间而变化因此每个连接都将具有不同的ISN。ISN可以看作是一个32比特的计数器每4ms加1 。这样选择序号的目的在于防止在网络中被延迟的分组在以后又被传送而导致某个连接的一方对它做错误的解释。三次握手的其中一个重要功能是客户端和服务端交换 ISN(Initial Sequence Number)以便让对方知道接下来接收数据的时候如何按序列号组装数据。如果 ISN 是固定的攻击者很容易猜出后续的确认号因此 ISN 是动态生成的。对于连接的3次握手主要是要初始化Sequence Number 的初始值。通信的双方要互相通知对方自己的初始化的Sequence Number缩写为ISNInital Sequence Number。这个号要作为以后的数据通信的序号以保证应用层接收到的数据不会因为网络上的传输的问题而乱序TCP会用这个序号来拼接数据。1.4 三次握手过程中可以携带数据吗其实第三次握手的时候是可以携带数据的。但是第一次、第二次握手不可以携带数据。为什么这样呢?大家可以想一个问题假如第一次握手可以携带数据的话如果有人要恶意攻击服务器那他每次都在第一次握手中的 SYN 报文中放入大量的数据。因为攻击者根本就不理服务器的接收、发送能力是否正常然后疯狂着重复发 SYN 报文的话这会让服务器花费很多时间、内存空间来接收这些报文。也就是说第一次握手不可以放数据其中一个简单的原因就是会让服务器更加容易受到攻击了。而对于第三次的话此时客户端已经处于 ESTABLISHED 状态。对于客户端来说他已经建立起连接了并且也已经知道服务器的接收、发送能力是正常的了所以能携带数据也没啥毛病。1.5 SYN攻击是什么服务器端的资源分配是在二次握手时分配的而客户端的资源是在完成三次握手时分配的所以服务器容易受到SYN洪泛攻击。SYN攻击就是Client在短时间内伪造大量不存在的IP地址并向Server不断地发送SYN包Server则回复确认包并等待Client确认由于源地址不存在因此Server需要不断重发直至超时这些伪造的SYN包将长时间占用未连接队列导致正常的SYN请求因为队列满而被丢弃从而引起网络拥塞甚至系统瘫痪。SYN 攻击是一种典型的 DoS/DDoS 攻击。检测 SYN 攻击非常的方便当你在服务器上看到大量的半连接状态时特别是源IP地址是随机的基本上可以断定这是一次SYN攻击。在 Linux/Unix 上可以使用系统自带的 netstat 命令来检测 SYN 攻击。netstat -n -p TCP | grep SYN_RECV常见的防御 SYN 攻击的方法有如下几种缩短超时SYN Timeout时间增加最大半连接数过滤网关防护SYN cookies技术关于SYN Flood攻击。一些恶意的人就为此制造了SYN Flood攻击——给服务器发了一个SYN后就下线了于是服务器需要默认等63s才会断开连接这样攻击者就可以把服务器的syn连接的队列耗尽让正常的连接请求不能处理。于是Linux下给了一个叫tcp_syncookies的参数来应对这个事——当SYN队列满了后TCP会通过源地址端口、目标地址端口和时间戳打造出一个特别的Sequence Number发回去又叫cookie如果是攻击者则不会有响应如果是正常连接则会把这个 SYN Cookie发回来然后服务端可以通过cookie建连接即使你不在SYN队列中。请注意请先千万别用tcp_syncookies来处理正常的大负载的连接的情况。因为synccookies是妥协版的TCP协议并不严谨。对于正常的请求你应该调整三个TCP参数可供你选择第一个是tcp_synack_retries可以用他来减少重试次数第二个是tcp_max_syn_backlog可以增大SYN连接数第三个是tcp_abort_on_overflow处理不过来干脆就直接拒绝连接了。1.6 第三次握手失败怎么办当第三次握手失败时服务器并不会重传ack报文而是直接发送RST报文段进入CLOSED状态。这样做的目的是为了防止SYN洪泛攻击。1.7 三次握手小结三次握手建立连接的首要目的是同步序列号。只有同步了序列号才有可靠的传输TCP 协议的许多特性都是依赖序列号实现的比如流量控制、消息丢失后的重发等等这也是三次握手中的报文被称为 SYN 的原因因为 SYN 的全称就叫做 Synchronize Sequence Numbers。1.7.1 客户端客户端发送 SYN 开启了三次握手之后客户端连接的状态是 SYN_SENT然后等待服务器回复 ACK 报文。正常情况下服务器会在几毫秒内返回 ACK但如果客户端迟迟没有收到 ACK 会怎么样呢客户端会重发 SYN重试的次数由tcp_syn_retries参数控制默认是 6 次net.ipv4.tcp_syn_retries 6第 1 次重试发生在 1 秒钟后接着会以翻倍的方式在第 2、4、8、16、32 秒共做 6 次重试最后一次重试会等待 64 秒如果仍然没有返回 ACK才会终止三次握手。所以总耗时是 1248163264127 秒超过 2 分钟。如果这是一台有明确任务的服务器你可以根据网络的稳定性和目标服务器的繁忙程度修改重试次数调整客户端的三次握手时间上限。比如内网中通讯时就可以适当调低重试次数尽快把错误暴露给应用程序。1.7.2 服务端当服务器收到 SYN 报文后服务器会立刻回复SYNACK报文既确认了客户端的序列号也把自己的序列号发给了对方。此时服务器端出现了新连接状态是 SYN_RCVD。这个状态下服务器必须建立一个SYN 半连接队列来维护未完成的握手信息当这个队列溢出后服务器将无法再建立新连接。如果 SYN 半连接队列已满只能丢弃连接吗并不是这样开启syncookies功能就可以在不使用 SYN 队列的情况下成功建立连接。syncookies 是这么做的服务器根据当前状态计算出一个值放在己方发出的 SYNACK 报文中发出当客户端返回 ACK 报文时取出该值验证如果合法就认为连接建立成功如下图所示。Linux 下怎样开启 syncookies 功能呢修改tcp_syncookies参数即可其中值为 0 时表示关闭该功能2 表示无条件开启功能而 1 则表示仅当 SYN 半连接队列放不下时再启用它。由于 syncookie 仅用于应对SYN 泛洪攻击攻击者恶意构造大量的 SYN 报文发送给服务器造成 SYN 半连接队列溢出导致正常客户端的连接无法建立这种方式建立的连接许多 TCP 特性都无法使用。所以应当把 tcp_syncookies 设置为 1仅在队列满时再启用。当客户端接收到服务器发来的 SYNACK 报文后就会回复 ACK 去通知服务器同时己方连接状态从 SYN_SENT 转换为 ESTABLISHED表示连接建立成功。服务器端连接成功建立的时间还要再往后到它收到 ACK 后状态才变为 ESTABLISHED。如果服务器没有收到 ACK就会一直重发 SYNACK 报文。当网络繁忙、不稳定时报文丢失就会变严重此时应该调大重发次数。反之则可以调小重发次数。tcp_synack_retries的默认重试次数是5 次与客户端重发 SYN 类似它的重试会经历 1、2、4、8、16 秒最后一次重试后等待 32 秒若仍然没有收到 ACK才会关闭连接故共需要等待63 秒。服务器收到 ACK 后连接建立成功此时内核会把连接从 SYN 半连接队列中移出再移入 accept 队列等待进程调用 accept 函数时把连接取出来。如果进程不能及时地调用 accept 函数就会造成 accept 队列溢出最终导致建立好的 TCP 连接被丢弃。实际上丢弃连接只是 Linux 的默认行为我们还可以选择向客户端发送RST 复位报文告诉客户端连接已经建立失败。打开这一功能需要将tcp_abort_on_overflow参数设置为 1。2. 四次挥手建立一个连接需要三次握手而终止一个连接要经过四次挥手也有将四次挥手叫做四次握手的。这由TCP的半关闭half-close造成的。所谓的半关闭其实就是TCP提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力。TCP 连接的拆除需要发送四个包因此称为四次挥手(Four-way handshake)客户端或服务端均可主动发起挥手动作。刚开始双方都处于ESTABLISHED状态假如是客户端先发起关闭请求。四次挥手的过程如下第一次挥手客户端发送一个 FIN 报文报文中会指定一个序列号。此时客户端处于FIN_WAIT1状态。即发出连接释放报文段FIN1序号sequ并停止再发送数据主动关闭TCP连接进入FIN_WAIT1终止等待1状态等待服务端的确认。第二次挥手服务端收到 FIN 之后会发送 ACK 报文且把客户端的序列号值 1 作为 ACK 报文的序列号值表明已经收到客户端的报文了此时服务端处于CLOSE_WAIT状态。即服务端收到连接释放报文段后即发出确认报文段ACK1确认号acku1序号seqv服务端进入CLOSE_WAIT关闭等待状态此时的TCP处于半关闭状态客户端到服务端的连接释放。客户端收到服务端的确认后进入FIN_WAIT2终止等待2状态等待服务端发出的连接释放报文段。第三次挥手如果服务端也想断开连接了和客户端的第一次挥手一样发给 FIN 报文且指定一个序列号。此时服务端处于LAST_ACK的状态。即服务端没有要向客户端发出的数据服务端发出连接释放报文段FIN1ACK1序号seqw确认号acku1服务端进入LAST_ACK最后确认状态等待客户端的确认。第四次挥手客户端收到 FIN 之后一样发送一个 ACK 报文作为应答且把服务端的序列号值 1 作为自己 ACK 报文的序列号值此时客户端处于TIME_WAIT状态。需要过一阵子以确保服务端收到自己的 ACK 报文之后才会进入 CLOSED 状态服务端收到 ACK 报文之后就处于关闭连接了处于CLOSED状态。即客户端收到服务端的连接释放报文段后对此发出确认报文段ACK1sequ1ackw1客户端进入TIME_WAIT时间等待状态。此时TCP未释放掉需要经过时间等待计时器设置的时间2MSL后客户端才进入CLOSED状态。收到一个FIN只意味着在这一方向上没有数据流动。客户端执行主动关闭并进入TIME_WAIT是正常的服务端通常执行被动关闭不会进入TIME_WAIT状态。在socket编程中任何一方执行close()操作即可产生挥手操作。通过上面的分析可以看出四次挥手涉及两种报文FIN 和 ACK。FIN 就是 Finish 结束连接的意思谁发出 FIN 报文就表示它将不再发送任何数据关闭这一方向的传输通道。ACK 是 Acknowledge 确认的意思它用来通知对方你方的发送通道已经关闭。四次挥手过程总结当主动方关闭连接时会发送 FIN 报文此时主动方的连接状态由 ESTABLISHED 变为FIN_WAIT1。当被动方收到 FIN 报文后内核自动回复 ACK 报文连接状态由 ESTABLISHED 变为CLOSE_WAIT顾名思义它在等待进程调用 close 函数关闭连接。当主动方接收到这个 ACK 报文后连接状态由 FIN_WAIT1 变为FIN_WAIT2主动方的发送通道就关闭了。再来看被动方的发送通道是如何关闭的。当被动方进入 CLOSE_WAIT 状态时进程的 read 函数会返回 0这样开发人员就会有针对性地调用close 函数进而触发内核发送 FIN 报文此时被动方连接的状态变为LAST_ACK。当主动方收到这个 FIN 报文时内核会自动回复 ACK同时连接的状态由 FIN_WAIT2 变为 TIME_WAITLinux 系统下大约1 分钟后 TIME_WAIT 状态的连接才会彻底关闭。而被动方收到 ACK 报文后连接就会关闭。2.1 挥手为什么需要四次这是因为 TCP 不允许连接处于半打开状态时就单向传输数据所以在三次握手建立连接时服务器会把 ACK 和 SYN 放在一起发给客户端其中ACK 用来打开客户端的发送通道SYN 用来打开服务器的发送通道。这样原本的四次握手就降为三次握手了。但是当连接处于半关闭状态时TCP 是允许单向传输数据的。为便于理解我们把先关闭连接的一方叫做主动方后关闭连接的一方叫做被动方。当主动方关闭连接时被动方仍然可以在不调用 close 函数的状态下长时间发送数据此时连接处于半关闭状态。这一特性是 TCP 的双向通道互相独立所致却也使得关闭连接必须通过四次挥手才能做到。2.2 2MSL等待状态TIME_WAIT状态也称为2MSL等待状态。每个具体TCP实现必须选择一个报文段最大生存时间MSLMaximum Segment Lifetime它是任何报文段被丢弃前在网络内的最长时间。这个时间是有限的因为TCP报文段以IP数据报在网络内传输而IP数据报则有限制其生存时间的TTL字段。对一个具体实现所给定的MSL值处理的原则是当TCP执行一个主动关闭并发回最后一个ACK该连接必须在TIME_WAIT状态停留的时间为2倍的MSL。这样可让TCP再次发送最后的ACK以防这个ACK丢失另一端超时并重发最后的FIN。这种2MSL等待的另一个结果是这个TCP连接在2MSL等待期间定义这个连接的插口客户的IP地址和端口号服务器的IP地址和端口号不能再被使用。这个连接只能在2MSL结束后才能再被使用。2.3 四次挥手释放连接时等待2MSL的意义?MSL是Maximum Segment Lifetime的英文缩写可译为“最长报文段寿命”它是任何报文在网络上存在的最长时间超过这个时间报文将被丢弃。为了保证客户端发送的最后一个ACK报文段能够到达服务器。因为这个ACK有可能丢失从而导致处在LAST-ACK状态的服务器收不到对FIN-ACK的确认报文。服务器会超时重传这个FIN-ACK接着客户端再重传一次确认重新启动时间等待计时器。最后客户端和服务器都能正常的关闭。假设客户端不等待2MSL而是在发送完ACK之后直接释放关闭一但这个ACK丢失的话服务器就无法正常的进入关闭连接状态。两个理由保证客户端发送的最后一个ACK报文段能够到达服务端。这个ACK报文段有可能丢失使得处于LAST-ACK状态的服务端收不到对已发送的FINACK报文段的确认服务端超时重传FINACK报文段而客户端能在2MSL时间内收到这个重传的FINACK报文段接着客户端重传一次确认重新启动2MSL计时器最后客户端和服务端都进入到CLOSED状态若客户端在TIME-WAIT状态不等待一段时间而是发送完ACK报文段后立即释放连接则无法收到服务端重传的FINACK报文段所以不会再发送一次确认报文段则服务端无法正常进入到CLOSED状态。防止“已失效的连接请求报文段”出现在本连接中。客户端在发送完最后一个ACK报文段后再经过2MSL就可以使本连接持续的时间内所产生的所有报文段都从网络中消失使下一个新的连接中不会出现这种旧的连接请求报文段。关于 MSL 和 TIME_WAIT。通过上面的ISN的描述相信你也知道MSL是怎么来的了。我们注意到在TCP的状态图中从TIME_WAIT状态到CLOSED状态有一个超时设置这个超时设置是 2*MSLRFC793定义了MSL为2分钟Linux设置成了30s为什么要这有TIME_WAIT为什么不直接给转成CLOSED状态呢主要有两个原因1TIME_WAIT确保有足够的时间让对端收到了ACK如果被动关闭的那方没有收到Ack就会触发被动端重发Fin一来一去正好2个MSL2有足够的时间让这个连接不会跟后面的连接混在一起你要知道有些自做主张的路由器会缓存IP数据包如果连接被重用了那么这些延迟收到的包就有可能会跟新连接混在一起。2.4 为什么TIME_WAIT状态需要经过2MSL才能返回到CLOSE状态TIME_WAIT 状态的连接在主动方看来确实已经关闭了。然而被动方没有收到 ACK 报文前连接还处于 LAST_ACK 状态。如果这个 ACK 报文没有到达被动方被动方就会重发FIN 报文。如果主动方不保留 TIME_WAIT 状态会发生什么呢此时连接的端口恢复了自由身可以复用于新连接了。然而被动方的 FIN 报文可能再次到达这既可能是网络中的路由器重复发送也有可能是被动方没收到 ACK 时基于 tcp_orphan_retries 参数重发。这样正常通讯的新连接就可能被重复发送的 FIN 报文误关闭。保留 TIME_WAIT 状态就可以应付重发的 FIN 报文当然其他数据报文也有可能重发所以 TIME_WAIT 状态还能避免数据错乱。理论上四个报文都发送完毕就可以直接进入CLOSE状态了但是可能网络是不可靠的有可能最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。2.5 TIME-WAIT状态过多怎么办TIME-WAIT状态如果过多会占用系统资源。Linux下有几个参数可以调整TIME-WAIT状态时间net.ipv4.tcp_tw_reuse 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接默认为0表示关闭。net.ipv4.tcp_tw_recycle 1 表示开启TCP连接中TIME-WAIT sockets的快速回收默认为0表示关闭。net.ipv4.tcp_max_tw_buckets 5000表示系统同时保持TIME_WAIT套接字的最大数量如果超过这个数字TIME_WAIT套接字将立刻被清除并打印警告信息。默认为180000改为5000。在socket的TIME_WAIT状态结束之前该socket所占用的本地端口号将一直无法释放。高TCP并发并且采用短连接方式进行通讯的通讯系统在高并发高负载下运行一段时间后就常常会出现做为客户端的程序无法向服务端建立新的socket连接的情况。此时用“netstat -tanlp”命令查看系统将会发现机器上存在大量处于TIME_WAIT状态的socket连接并且占用大量的本地端口号。最后当该机器上的可用本地端口号被占完或者达到用户可使用的文件句柄上限而旧的大量处于TIME_WAIT状态的socket尚未被系统回收时就会出现无法向服务端创建新的socket连接的情况。此时系统几乎停转空有再好的性能也发挥不出来。解决TIME-WAIT状态过多的情况一般做法是打开系统的TIMEWAIT重用和快速回收。然而主动进行关闭的链接才会进入TIME-WAIT状态所以最好的办法尽量不要让服务器主动关闭链接除非一些异常情况如客户端协议错误、客户端超时等等。解决方法修改TIME_WAIT连接状态的上限值启动快速回收机制开启复用机制修改短连接为长连接方式由客户端来主动断开连接3. 总结《TCP/IP详解 卷1:协议》有一张TCP状态变迁图很具有代表性有助于大家理解三次握手和四次挥手的状态变化。如下图所示粗的实线箭头表示正常的客户端状态变迁粗的虚线箭头表示正常的服务器状态变迁。以后面试官再问你三次握手和四次挥手直接把这一篇文章丢给他就可以了他想问的都在这里。