全网最全计算机网络排查八股文讲解(25秋招走起~)

TCP和UDP的主要区别是什么?

TCP(传输控制协议)和UDP(用户数据报协议)的主要区别在于TCP是面向连接的协议,而UDP是无连接的协议。这导致了它们在数据传输方式、可靠性、速度和使用场景方面的不同。

1、连接方式: TCP是面向连接的协议,数据传输前需要三次握手建立连接。UDP是无连接的,发送数据前不需要建立连接。

2、可靠性: TCP提供可靠的数据传输,通过序号、确认应答、重传机制等确保数据完整性。UDP不保证数据的可靠传输,不进行错误检查和修正。

3、速度和效率: UDP由于没有建立连接的过程,使得其在数据传输速度上比TCP更快,适用于对实时性要求高的场景。

4、使用场景: TCP用于需要可靠传输的应用,如网页浏览、文件传输。UDP常用于直播、在线游戏等对速度敏感的应用。

HTTP协议的主要特点是什么?

HTTP(超文本传输协议)是一种无状态的应用层协议,用于从服务器传输超文本到本地浏览器。它的主要特点包括:

1、简单快速: 客户端向服务器请求时,只需传送请求方法和路径。服务器响应快速简单。

2、灵活: HTTP允许传输任意类型的数据对象。通过Content-Type标头,客户端和服务器可以进行内容协商。

3、无状态: HTTP协议自身不对请求和响应之间的通信状态进行保存。但可以通过在请求和响应消息中加入cookie来实现状态管理。

4、支持B/S及C/S模式: 最常用于浏览器/服务器(B/S)模式的通信,也支持客户端/服务器(C/S)模式。

Socket编程中TCP和UDP编程的区别?

在Socket编程中,TCP和UDP的使用区别主要体现在连接建立、数据传输安全性、效率和编程复杂度上。

1、连接建立: 使用TCP的Socket编程需要先建立连接,经过三次握手过程。UDP的Socket编程不需要建立连接,可以直接发送数据。

2、数据传输安全性: TCP保证了数据的顺序、可靠性和数据完整性。UDP则不能保证这些,可能会出现数据丢失、重复或顺序错误的情况。

3、效率: 由于UDP的传输机制简单,通常它的数据传输效率比TCP要高,尤其是在要求高实时性的应用中。

4、编程复杂度: TCP编程相比UDP编程,由于需要处理连接的建立、维护和断开,所以相对复杂一些。

什么是网络协议栈?

网络协议栈,也称为TCP/IP协议栈,是一系列网络通信协议的集合,用于实现网络设备间的数据交换和通信。网络协议栈分为不同的层次,每一层都有特定的功能和协议。

1、应用层: 提供网络应用程序以及它们之间的通信服务,例如HTTP、FTP、SMTP等。

2、传输层: 负责提供端到端的数据传输服务,主要协议包括TCP和UDP。

3、网络层: 负责数据包从源到目的地的传输和路由选择,主要协议是IP协议。

4、链路层: 负责网络实体间数据帧的传送和接收,处理物理介质的接入问题,例如以太网。

这些层次协同工作,确保数据准确、高效地在网络中传输。

TCP三次握手过程是什么?

TCP三次握手过程是TCP协议建立一个连接的过程,它确保双方都准备好进行数据传输。这个过程涉及三个步骤:

1、SYN: 客户端发送一个SYN(同步序列编号)报文到服务器。在这个阶段,客户端尝试建立连接,发送包含初始序列号的数据包给服务器,表明客户端希望开始通信。

2、SYN-ACK: 服务器接收到客户端的SYN请求后,会返回一个SYN-ACK(同步应答)报文。该报文中的ACK确认客户端的SYN,同时服务器自己也发送一个SYN请求,询问客户端是否准备好接收数据。

3、ACK: 客户端收到服务器的SYN-ACK响应后,发送一个ACK(确认)报文。这个ACK报文确认了服务器的SYN,至此,连接建立成功,数据传输可以开始。

这个过程是建立TCP连接的关键,确保了双方的通信是同步的,且数据传输是可靠的。

如何理解HTTP协议的无状态性?

HTTP协议的无状态性意味着每次请求之间是相互独立的,服务器不会保存任何请求的状态。这个特点有以下几个方面的理解:

1、请求独立: 每次HTTP请求都是独立的,服务器处理完请求后不会记住这个请求的任何信息。

2、会话管理: 虽然HTTP本身是无状态的,但可以通过Cookies、Session等技术在客户端和服务器之间维护状态,实现状态的连续性。

3、性能和扩展性: 无状态性简化了服务器的设计,因为服务器不需要去管理和存储请求状态。这提高了服务器的性能和可扩展性。

4、应用场景: 无状态性使得HTTP协议特别适用于分布式系统中,每个请求都可以独立处理,易于负载均衡和缓存。

UDP的校验机制是如何工作的?

UDP的校验机制是通过在UDP头部添加一个校验和(Checksum)字段来实现的。这个过程具体包括:

1、计算校验和: 发送端在发送数据之前,会计算出包含UDP头部和数据部分的校验和。这个校验和是通过将UDP数据包分为16位字节段后进行一系列的二进制求和操作得到的。

2、验证校验和: 接收端收到数据包后,会对包含校验和的整个数据包进行同样的计算。如果计算结果与接收到的校验和一致,说明数据在传输过程中未发生改变,数据完整性得到验证。

3、错误处理: 如果校验和不匹配,表明数据包在传输过程中可能被损坏,UDP协议通常会丢弃这个数据包,而不是尝试修复它。

UDP的校验机制提供了基本的数据完整性验证,但不像TCP那样提供复杂的错误恢复机制。

Socket编程中如何实现多客户端通信?

在Socket编程中,实现多客户端通信通常涉及到服务器端使用多线程或多进程来处理来自不同客户端的连接请求。具体方法包括:

1、多线程: 服务器为每个新连接的客户端创建一个新的线程。这样,每个客户端都有一个独立的线程在服务端进行通信处理。

2、多进程: 类似于多线程,服务器为每个新连接的客户端创建一个新的进程。这种方式在资源消耗上比线程大,但进程间的隔离性更好。

3、非阻塞IO(NIO): 使用非阻塞IO模型可以让一个线程处理多个连接请求。这是通过轮询各个连接请求并处理就绪的IO事件来实现的。

4、事件驱动模型: 使用事件驱动的方式(如使用选择器Selector)来监听和处理事件,使得单个线程能高效处理多个客户端的请求。

这些方法各有优缺点,选择合适的模型取决于应用的具体需求和预期的性能表现。

TCP如何实现流量控制?

TCP实现流量控制的机制主要是通过窗口大小(Window Size)来实现的,这个过程包含以下几个关键点:

1、窗口大小: TCP头部有一个窗口大小字段,用于告诉对方自己的接收缓冲区还能接受多少字节的数据,从而控制发送方的发送速率。

2、滑动窗口协议: TCP使用滑动窗口协议进行流量控制。发送方根据接收方提供的窗口大小来决定可以发送的数据量,确保接收方能够有效处理接收到的数据。

3、动态调整: 窗口大小不是固定的,而是会根据网络状况和接收方处理能力动态调整,以达到高效和公平的数据传输。

4、阻塞控制: 当接收方处理不过来时,它可以通过发送较小的窗口大小值甚至是零窗口来通知发送方减慢发送速度或暂停发送,避免数据溢出。

通过这些机制,TCP能够有效地控制数据流量,保证网络的稳定性和数据的可靠传输。

HTTP和HTTPS有哪些主要区别?

HTTP和HTTPS的主要区别在于安全性和数据传输加密上,具体如下:

1、加密传输: HTTPS协议通过SSL或TLS为数据传输提供了加密,保障了数据传输的安全性。而HTTP传输的数据是未加密的,容易被第三方截获和篡改。

2、端口不同: 通常,HTTP使用80端口进行通信,而HTTPS使用443端口。

3、性能影响: HTTPS由于加密过程增加了数据包的大小,并且加密解密过程需要消耗额外的计算资源,因此相比HTTP有一定的性能影响。

4、证书要求: 使用HTTPS需要获取并安装SSL证书,以证明服务器的身份。这增加了一定的成本和维护工作。

UDP数据包的最大长度是多少?

UDP数据包的最大长度受到UDP头部的长度字段的限制。UDP头部的长度字段是16位的,最大可以表示的数值是65535,但是需要从中扣除UDP头部本身的长度(8字节),因此,理论上UDP数据包的最大长度是65527字节(65535-8)。

但是,实际使用中还需要考虑IP层的限制,IP数据报的最大长度也是65535字节,包括IP头部和数据部分。因此,当考虑IP头部的长度时(通常20字节到60字节不等),UDP数据包的实际可用最大长度会进一步减少。

什么是Socket,它在网络编程中扮演什么角色?

Socket是网络编程中的一个抽象概念,它是提供网络通信功能的一种方式。在操作系统中,Socket是开放给应用程序的编程接口(API),允许程序员实现进程之间的通信。

1、通信端点: Socket充当网络通信的端点,每个使用网络通信的应用程序至少需要一对Socket(服务器端和客户端)。

2、数据交换: Socket用于在网络中不同主机的应用程序之间交换数据。它支持多种通信协议,如TCP和UDP,以适应不同的网络通信需求。

3、编程接口: 提供了一组API,允许开发者在应用程序中实现网络功能,如连接、发送数据和接收数据等。

4、支撑多种语言和平台: Socket编程接口在多种编程语言和操作系统平台上都有支持,使得跨平台网络编程成为可能。

通过Socket,开发者可以构建复杂的网络应用程序,实现数据的实时传输和高效的网络通信。

TCP如何处理网络拥塞?

TCP处理网络拥塞的机制主要包括拥塞控制算法,如慢启动、拥塞避免、快速重传和快速恢复等。这些算法共同作用,以避免网络过载,确保网络的稳定性和数据传输的可靠性:

1、慢启动: TCP连接开始时,先以小的拥塞窗口发送数据,然后随着每次成功的传输而指数增加窗口大小,直到达到阈值。

2、拥塞避免: 当窗口大小达到阈值后,算法转为线性增长,逐渐增加拥塞窗口的大小,以避免网络突然拥塞。

3、快速重传: 当发送方收到三个重复的ACK时,立即重传未被确认的数据包,而不是等待超时,以快速恢复数据传输。

4、快速恢复: 在快速重传后,减半当前的拥塞窗口和阈值,然后进入拥塞避免阶段,逐渐增加窗口大小,而不是重新开始慢启动。

通过这些策略,TCP能够动态调整数据的发送速率,减少网络拥塞的可能性,提高数据传输效率。

HTTP/2相比HTTP/1.x有哪些显著改进?

HTTP/2相比于HTTP/1.x引入了多项改进,旨在提高网络通信的效率和速度:

1、二进制帧层: HTTP/2引入了二进制格式,将所有传输的信息分割为更小的消息和帧,并对它们进行二进制编码,提高了传输效率。

2、多路复用: 允许同时通过单一的HTTP/2连接发送多个请求和响应消息,消除了HTTP/1.x中的队头阻塞问题,大大提高了页面加载速度。

3、头部压缩: HTTP/2使用HPACK压缩格式减小了头部大小,减少了传输的数据量。

4、服务器推送: 服务器可以在客户端请求之前发送数据,提高了资源加载的效率。

这些改进使HTTP/2在性能上较HTTP/1.x有了显著的提升,尤其是在复杂或延迟高的网络条件下。

在UDP中如何实现可靠的数据传输?

尽管UDP本身是不可靠的协议,但可以通过在应用层实现一些机制来达到可靠的数据传输:

1、应用层确认和重传机制: 发送方在发送数据后,等待接收方的确认响应。如果在指定时间内没有收到确认,发送方会重传数据。

2、序列号: 给数据包编号,以确保数据的顺序性和完整性。接收方可以通过序列号检查是否有数据包丢失,并请求重传。

3、校验和: 使用校验和验证数据完整性,检测数据在传输过程中是否被篡改或损坏。

4、流量控制: 类似于TCP的流量控制,根据接收方的处理能力调整发送速率,避免接收方被过多的数据淹没。

通过这些策略,即使是使用UDP,应用程序也能实现相对可靠的数据传输机制。

Socket编程中的阻塞与非阻塞模式有何区别?

在Socket编程中,阻塞与非阻塞模式的主要区别在于对I/O操作的处理方式不同:

1、阻塞模式(Blocking Mode): 在这种模式下,I/O调用会挂起调用线程的执行,直到操作完成。例如,如果数据还未到达,一个阻塞的读操作会使调用线程挂起,直到有数据可读。

2、非阻塞模式(Non-blocking Mode): 在非阻塞模式下,I/O调用会立即返回,无论操作是否完成。如果操作不能立即完成,调用会返回一个错误码,通常是指示"操作会阻塞"的错误。应用程序可以继续执行其他任务或定期检查操作是否完成。

非阻塞模式允许应用程序以异步方式进行I/O操作,提高了程序的效率和响应性,特别是在处理多个Socket连接时。

TCP如何保证数据传输的顺序性和可靠性?

TCP保证数据传输的顺序性和可靠性通过以下几个核心机制:

1、序列号: 每个TCP段都被赋予一个序列号,用于保证数据的顺序性。接收方根据序列号将数据重新排序,以确保数据的正确顺序。

2、确认应答: 接收方收到数据后,会发送一个确认应答(ACK),表明已成功接收到该数据段。发送方未收到确认应答的数据会被重新发送。

3、数据校验: TCP头部包含一个校验和字段,用于检查数据在传输过程中是否出现错误,保证数据的完整性。

4、流量控制: 通过滑动窗口机制,接收方可以控制发送方的数据发送速率,防止接收缓冲区被溢出。

5、拥塞控制: TCP使用拥塞控制算法如慢启动、拥塞避免、快速重传和快速恢复等,根据网络状况调整数据的发送速率,保证网络不会因为过载而崩溃。

通过这些机制,TCP能够确保数据以正确的顺序安全可靠地传输。

HTTP协议中状态码301和302有什么区别?

HTTP状态码301和302都用于实现URL的重定向,但它们的使用场景和含义有所区别:

1、301 Moved Permanently: 表示请求的资源已被永久移动到新位置,搜索引擎在索引时会用新的URL替换掉旧的URL,适用于资源永久移动的场景。

2、302 Found: 表示请求的资源临时被移动到另一个URI,客户端应该使用新的URI进行后续的请求,但搜索引擎会继续索引原有的URL,适用于资源临时移动的场景。

主要区别在于301是永久性转移,302是临时性转移。选择哪一个取决于资源移动的性质。

UDP协议如何减少数据包的丢失?

虽然UDP本身不提供保证数据包传输可靠性的机制,但应用程序可以实现一些策略来减少数据包的丢失:

1、重传机制: 对于重要的数据包,应用程序可以实现超时重传机制。如果在指定的时间内未收到接收端的确认,发送端可以重新发送数据包。

2、序列号: 为数据包分配序列号,接收方可以检测数据包是否有丢失,并可以请求发送方重传丢失的包。

3、数据冗余: 发送重要数据的副本或者采用纠错编码技术,即使丢失部分数据包,接收方也能恢复原始数据。

4、调整发送频率: 根据网络状况调整数据的发送速率,避免因网络拥塞导致的数据包丢失。

通过这些方法,可以在UDP协议的基础上,提高数据传输的可靠性。

Socket通信中的Nagle算法是什么?它如何工作?

Nagle算法是一种在TCP协议中减少网络拥塞和提高网络效率的算法。它的工作原理如下:

1、数据缓冲: Nagle算法通过缓冲待发送的小数据包,直到累积到一个足够大的数据包或收到之前发送的数据包的ACK,再一次性发送。

2、减少小包的发送: 该算法的目的是减少网络上小数据包的数量,因为大量的小数据包会增加网络的负载,降低效率。

3、条件发送: 只有当所有先前发送的数据包都已经得到确认,或者缓冲区已满,才发送数据。这样做可以聚合多个小的输出操作到一个较大的数据包。

4、提高网络利用率: Nagle算法通过减少需要传输的数据包的数量,来优化网络的利用率,特别是在交互式应用程序中效果显著。

在某些需要低延迟的应用中,可能会禁用Nagle算法,以避免数据发送的延迟。

TCP协议如何实现可靠性传输的错误检测?

TCP实现可靠性传输的错误检测主要依赖于以下机制:

1、序列号和确认应答: TCP为每个数据包分配一个序列号,并要求接收方对收到的数据包发送确认应答(ACK)。通过这种方式,发送方可以知道哪些数据包已成功接收,哪些需要重传。

2、校验和: 每个TCP数据包包含一个校验和字段,用于检查数据在传输过程中是否出现错误。接收方计算收到的数据包的校验和,如果计算结果与数据包中的校验和不符,说明数据在传输中被损坏,接收方不会发送ACK,发送方在超时后会重传该数据包。

3、超时重传: 如果发送方在预定时间内没有收到对某个数据包的确认应答,它会重新发送该数据包。

4、流量控制和拥塞控制: 通过调整发送速率和控制数据流,TCP确保网络容量不会被过度使用,减少数据包丢失和错误的可能性。

这些机制共同确保了TCP协议的高可靠性,在数据传输过程中能够有效地检测和纠正错误。

HTTP Keep-Alive机制的作用是什么?

HTTP Keep-Alive机制,也称为持久连接,主要作用是减少服务器负载,提高请求的响应速度。它的工作原理和优点包括:

1、连接复用: Keep-Alive允许在一个TCP连接上发送和接收多个HTTP请求/响应,而不是每次请求都需要重新建立和关闭连接。

2、减少延迟: 由于减少了建立和关闭连接的次数,减少了因TCP握手造成的延迟,从而提高了页面加载速度。

3、节省资源: 复用TCP连接减少了服务器和客户端需要同时打开的连接数,节约了网络资源和减轻了服务器负载。

4、易于管理: 通过控制连接的存活时间,可以更好地管理服务器资源,优化性能。

HTTP Keep-Alive机制通过复用TCP连接,为HTTP通信提供了效率和性能上的提升。

在Socket编程中,什么是半关闭(Half-close)?

在Socket编程中,半关闭(Half-close)是指连接的一方完成了它的数据发送任务,但仍然可以接收来自另一方的数据。半关闭的特点和应用场景包括:

1、关闭写操作: 半关闭允许一端通过关闭Socket的写功能来告知对方它已经发送完所有的数据,但这一端仍然可以接收对方发送的数据。

2、继续接收数据: 这种机制允许数据接收方知道发送方不会再发送更多的数据,但连接并未完全关闭,接收方仍可以发送数据给发送方。

3、优雅地关闭连接: 半关闭机制是TCP提供的一种优雅关闭连接的方式,确保双方数据的完整传输,特别是在需要单向通信完成后继续接收数据的应用中。

4、节省资源: 通过半关闭状态,应用程序可以更有效地管理资源,如在传输大量数据后关闭输出流,同时保持输入流开启,直至接收完毕。

半关闭状态提供了一种灵活的通信结束方式,允许数据传输的一方在完成发送后关闭输出流,而不完全终止连接。

描述TCP的快速重传和快速恢复机制。

TCP的快速重传和快速恢复是两种用于提高网络通信效率的机制,它们的工作原理如下:

快速重传: 当发送方接收到三个连续的重复确认(Duplicate ACKs),即接收方收到一个失序的数据包时,它会立即重传未被确认的数据包,而不是等待重传计时器到期。这减少了因为数据包丢失而导致的等待时间。

快速恢复: 在执行快速重传后,TCP不会将拥塞窗口减小到1个MSS(最大报文段大小)的慢启动阈值,而是减半当前的拥塞窗口和慢启动阈值,然后立即开始拥塞避免阶段。这意味着拥塞窗口的增长会比慢启动快,从而更快地恢复到丢包前的传输速率。

这两种机制共同作用,可以在发生丢包时快速恢复,减少超时重传对TCP连接性能的影响,提高数据传输的效率和可靠性。

解释TCP零窗口大小的情况和如何处理?

TCP零窗口大小的情况发生在接收方的接收缓冲区已满,无法再接受更多数据时。接收方会通知发送方其窗口大小为零,导致发送方暂停发送数据。处理这种情况的方法包括:

1、零窗口探测: 发送方在接收到零窗口通知后,会定期发送零窗口探测报文,查询接收方窗口是否已经开放。

2、窗口更新: 一旦接收方处理了足够的数据并释放了接收缓冲区的空间,它会发送一个窗口更新报文给发送方,通知其新的窗口大小,发送方随后可以恢复数据传输。

3、避免数据流停滞: 这一机制确保了即使在网络拥塞或接收方处理能力有限的情况下,数据传输也能最终恢复,避免了连接的长时间空闲或断开。

HTTP/1.1中的管道化(Pipelining)是什么意思?

HTTP/1.1中的管道化是一种技术,允许在同一个TCP连接中,客户端在收到前一个请求的响应之前,发送多个请求。这种机制的主要目的是减少延迟和提高通信效率。它的工作原理包括:

1、请求排队: 客户端可以连续发送多个请求而无需等待对前一个请求的响应。

2、顺序响应: 尽管请求可以批量发送,但服务器必须按请求接收的顺序依次响应,以保证响应和请求的对应关系。

3、提高效率: 通过减少等待时间和利用TCP连接的高效性,管道化可以使网页加载更快,尤其是在高延迟的网络上。

4、实际应用限制: 虽然HTTP/1.1规范中定义了管道化,但由于实现复杂性和兼容性问题,它在实际应用中并不广泛。

什么是UDP广播和多播?

UDP广播和多播是网络通信中用于数据发送的两种机制,允许数据包被发送给多个接收方。

广播(Broadcasting): 广播是将数据包发送到网络上的所有设备的过程。在广播中,数据包被发送到一个特殊的广播地址,网络上的所有设备都会接收到这个数据包。广播通常在单个网络段内使用。

多播(Multicasting): 多播允许数据包被送达给一组指定的接收方,而不是网络上的所有设备。使用多播时,数据发送到一个多播组地址,只有加入了这个多播组的成员才会接收到数据包。多播更加高效,适用于如视频会议和实时流媒体等应用。

1、节省带宽: 多播和广播可以有效地将数据同时发送给多个接收者,减少了网络带宽的消耗。

2、提高效率: 通过向多个接收者发送同一数据包,提高了数据传输的效率。

Socket编程中如何处理异步事件?

在Socket编程中处理异步事件通常涉及到非阻塞模式和事件驱动模型,这些方法允许应用程序在不被阻塞的情况下监听和响应网络事件。具体方法包括:

1、非阻塞Sockets: 将Socket设置为非阻塞模式,使得在执行操作如读取或写入时,即使操作未完成也会立即返回,应用程序可以继续执行其他任务。

2、事件选择器(Selectors): 使用选择器(Selectors)监听多个Sockets的事件,如连接、数据到达等。当事件发生时,选择器会通知应用程序,从而进行相应的处理。

3、异步IO(AIO): 在某些编程语言中,支持异步IO操作,允许程序在发起一个IO操作如数据读取后立即返回,IO操作完成时通过回调函数通知应用程序。

4、事件驱动框架: 使用如Node.js这样的事件驱动框架,可以简化异步事件的处理。这类框架内部使用事件循环监听和响应事件,开发者只需要注册事件处理函数即可。

这些方法使得应用程序可以高效地处理并发网络连接和数据传输,提高了应用程序的响应能力和性能。

TCP连接的建立和终止过程中发生的状态变化是什么?

TCP连接的建立和终止涉及一系列状态变化,这些状态变化确保了连接的可靠性和顺序性。

建立连接(三次握手):

  1. CLOSEDSYN_SENT: 客户端发送SYN包,开始尝试建立连接,状态从CLOSED变为SYN_SENT。
  2. LISTENSYN_RECEIVED: 服务器收到SYN包后,回复SYN+ACK包,状态从LISTEN变为SYN_RECEIVED。
  3. SYN_SENTESTABLISHED: 客户端收到SYN+ACK后,发送ACK包,状态变为ESTABLISHED,连接建立。

终止连接(四次挥手):

  1. ESTABLISHEDFIN_WAIT_1: 主动关闭的一方发送FIN包,请求关闭连接,状态变为FIN_WAIT_1。
  2. FIN_WAIT_1FIN_WAIT_2: 另一方回复ACK包,确认收到FIN,状态变为FIN_WAIT_2。
  3. FIN_WAIT_2TIME_WAIT: 当收到另一方的FIN包时,回复ACK包,状态变为TIME_WAIT,等待可能的重发FIN包。
  4. TIME_WAITCLOSED: 经过一段时间(2MSL,最大报文生存时间)后,确保对方收到了ACK包,连接完全关闭,状态回到CLOSED。

这个过程确保了TCP连接的可靠性和数据的完整性。

HTTP消息头中的Content-Type和Accept有什么作用?

Content-Type和Accept是HTTP消息头中用来指定媒体类型(MIME类型)的两个字段,它们的作用如下:

  1. Content-Type: 指示HTTP消息体的媒体类型。在响应中,它告诉客户端实际返回的内容类型;在请求中,它告诉服务器客户端能够发送的数据类型。例如,Content-Type: application/json表示消息体是JSON格式。
  2. Accept: 用于客户端请求中,指示客户端可以处理的媒体类型及其优先级。服务器根据这个头部信息决定返回哪种内容类型。例如,Accept: text/html表示客户端期望接收HTML格式的响应。

这两个头部字段使得HTTP能够支持多种格式的数据传输,提高了Web应用的灵活性和互操作性。

描述UDP数据传输的不可靠性及其应对策略。

UDP数据传输的不可靠性主要体现在三个方面:数据包的丢失、错误和顺序错乱。应对这些不可靠性的策略包括:

  1. 应用层确认机制: 通过在应用层实现确认机制,发送方可以确认数据包是否被接收方正确接收。
  2. 超时重传: 如果发送方在指定时间内没有收到确认,可以重新发送数据包。
  3. 序列号: 为每个数据包分配序列号,接收方可以通过序列号检查数据包是否按正确的顺序到达,并检测是否有数据包丢失。
  4. 校验和: 利用UDP自带的校验和进行错误检测,虽然不可以自动纠错,但可以发现错误并决定是否丢弃数据包或请求重发。

通过这些策略,应用程序可以在一定程度上弥补UDP的不可靠性,满足特定应用的需求。

Socket中bind函数的作用是什么?

在Socket编程中,bind函数的作用是将Socket与一个特定的IP地址和端口号绑定。这个过程对于服务器端的Socket尤其重要,因为它确保服务器监听一个确定的端口,客户端就可以通过这个端口与服务器建立连接。具体作用包括:

  1. 指定地址和端口: 通过bind函数,服务器可以指定一个具体的IP地址和端口号,用于接收来自客户端的连接请求。
  2. 端口复用: 在某些情况下,服务器需要重启,bind函数可以通过设置Socket选项来允许地址和端口的复用,避免“地址已被占用”的错误。
  3. 区分服务: 在同一台服务器上运行多个服务时,可以通过绑定不同的端口号来区分不同的服务。

bind函数是服务器端设置Socket的重要步骤之一,为建立网络连接提供了基础。

TCP头部包含哪些重要字段及其作用?

TCP头部包含多个字段,每个字段都有其特定的作用,关键字段包括:

1、源端口和目标端口: 标识发送和接收的应用程序端口号,用于数据的正确传输。

2、序列号: 用于数据包的顺序控制,确保数据的有序性。

3、确认应答号: 确认接收到对方发送的数据包的序列号。

4、数据偏移: 指示TCP头部的长度,用于数据开始的位置。

5、控制位: 包括SYN、ACK、FIN等标志,用于连接的建立、数据传输的确认和连接的终止。

6、窗口大小: 控制对方发送的数据量,用于流量控制。

7、校验和: 检验数据的完整性和正确性。

8、紧急指针: 指示紧急数据的结束位置,用于传输紧急数据。

这些字段共同作用,确保了TCP连接的可靠性和数据的正确传输。

HTTP/3的主要改进是什么?

HTTP/3是基于QUIC协议的新版HTTP协议,其主要改进包括:

1、基于UDP实现: 不同于之前的基于TCP的版本,HTTP/3使用QUIC(基于UDP),提高了传输速度和连接的可靠性。

2、减少连接建立时间: 通过QUIC协议,HTTP/3可以减少连接建立时的延迟,实现更快的数据传输。

3、改进的拥塞控制: QUIC内置的拥塞控制机制更加高效,能够更好地处理网络变化。

4、连接迁移支持: 支持连接迁移,即即使网络环境变化(如更换网络),连接也能保持不断。

5、更强的安全性: HTTP/3将加密和身份验证作为标准部分,提供了比HTTP/2更强的安全保障。

这些改进使HTTP/3在性能、可靠性和安全性方面都有显著提升。

描述TCP和UDP在网络编程中的适用场景。

TCP和UDP在网络编程中各有适用场景:

TCP适用场景:

  • 数据传输可靠性要求高:如文件传输、电子邮件、网页浏览等场景,需要确保数据完整性和顺序性。
  • 连接控制:需要建立稳定连接的应用,如远程登录。
  • 流量控制和拥塞控制:对网络质量要求较高的应用。

UDP适用场景:

  • 实时性要求高:如视频会议、实时游戏、语音通话等,UDP的低延迟特性更适合。
  • 广播和多播通信:UDP支持发送广播和多播消息,适用于多点通信。
  • 简单的查询-响应通信:不需要建立连接的服务,如DNS查询。

根据应用的具体需求选择适合的协议,可以更好地平衡性能和可靠性。

什么是WebSocket?它和HTTP有什么区别?

WebSocket是一种网络通信协议,提供了在单个TCP连接上进行全双工通信的能力。与HTTP的主要区别包括:

1、持久连接: WebSocket在客户端和服务器之间建立一个持久连接,允许双向数据流,而HTTP请求/响应模型则是短连接。

2、实时性: WebSocket提供更低的延迟通信,适合需要实时数据交换的应用,如在线游戏、实时交易平台。

3、数据帧: WebSocket通过数据帧传输数据,支持更高效的数据处理和较小的开销,而HTTP每次交换都需要完整的头部。

4、协议升级: WebSocket通信开始于HTTP请求,通过"Upgrade"头部将协议从HTTP升级到WebSocket。

WebSocket和HTTP各有特点,选择哪种协议取决于应用场景的具体需求,特别是是否需要实时通信和持久连接。

如何在TCP/IP模型中实现端到端的加密通信?

在TCP/IP模型中,实现端到端加密通信主要依赖于传输层和应用层的安全协议,如TLS(传输层安全协议)和SSL(安全套接层):

1、TLS/SSL: 这些协议在传输层提供加密功能,保证数据在Internet上的传输过程中不能被窃听或篡改。它们通过握手过程协商加密算法和密钥,然后对传输的数据进行加密。

2、应用层加密: 应用数据在发送之前,在应用层进行加密,确保即使在传输层被拦截,数据也因为加密而无法被理解。常见的应用层加密实现包括HTTPS、SSH等。

3、密钥交换机制: 使用如Diffie-Hellman密钥交换协议,允许双方在不安全的通道上协商出一个共享密钥,用于之后的通信加密。

通过这些机制,TCP/IP模型中的数据传输可以实现端到端的加密,提高数据传输的安全性。

HTTP状态码503和504的区别是什么?

HTTP状态码503和504都指示服务器端的错误,但具体含义和场景有所不同:

1、503 Service Unavailable: 表示服务器暂时处于超载或维护状态,无法处理请求。这是一个临时状态,意味着服务器在一段时间后可能恢复正常。

2、504 Gateway Timeout: 表示作为网关或代理的服务器,未能在允许的时间内从上游服务器(或其他辅助服务器)收到请求的响应。这通常表明上游服务器响应缓慢或不可达。

区别在于503关注的是服务器自身的问题,而504关注的是服务器尝试访问另一个服务时遇到的问题。

在网络编程中,非阻塞IO和异步IO的区别是什么?

非阻塞IO和异步IO都是提高网络应用性能和响应性的技术,但它们的工作方式有所不同:

1、非阻塞IO(Non-blocking IO): 在这种模式下,IO操作会立即返回,不会使程序阻塞等待。如果操作不能立即完成,调用会返回一个特定的状态码(如EWOULDBLOCK),应用程序可以决定后续操作,通常涉及轮询或选择器来检查IO状态。

2、异步IO(Asynchronous IO): 异步IO操作请求后,会立即返回,让程序继续执行。当IO操作完成时,通过回调函数、事件或信号等机制通知应用程序。应用程序不需要主动检查IO操作的完成状态。

主要区别在于处理IO操作完成的方式,非阻塞IO需要应用程序主动检查状态,而异步IO通过系统通知应用程序操作已完成。

描述IPv6相比IPv4的主要优势。

IPv6相比于IPv4,提供了多项改进和优势:

1、更大的地址空间: IPv6使用128位地址长度,相比IPv4的32位,提供了几乎无限的地址空间,解决了IPv4地址耗尽的问题。

2、简化的头部格式: IPv6的头部格式更为简化,提高了数据包处理的效率。

3、改进的路由效率: 由于地址的层次结构和简化的头部,IPv6改进了路由的效率和速度。

4、内建的安全性: IPv6设计时考虑了IPsec(网络层安全协议),为数据传输提供了内建的加密和认证。

5、更好的移动性支持: IPv6支持无缝移动性,使得设备在移动过程中可以保持持久的网络连接。

6、自动配置能力: IPv6支持无状态地址自动配置(SLAAC),设备可以自动获取网络地址,简化了网络配置过程。

这些优势使得IPv6成为了支持未来互联网发展的关键技术。

什么是TCP粘包问题,如何避免?

TCP粘包问题是指在TCP传输过程中,由于TCP是面向流的协议,多个发送的数据包在接收时可以被合并为一个数据包。这通常发生在发送方频繁发送小量数据或接收方不及时读取接收缓冲区时。避免粘包的方法包括:

1、消息定界: 在数据包开始或结束处添加特定的序列,如特殊字符或字符串,接收方根据这些序列分割数据包。

2、固定长度: 将每个数据包设计为固定长度,不足部分可以用空白填充。

3、长度前缀: 每个数据包前加上长度字段,表明数据包的长度,接收方根据这个长度字段来读取相应长度的数据。

HTTP方法GET和POST的区别是什么?

GET和POST是HTTP协议中最常用的两种方法,主要区别包括:

1、数据传输方式: GET通过URL传输数据,数据附加在URL后面,而POST将数据放在HTTP消息体中。

2、安全性: 由于GET的数据直接暴露在URL中,因此安全性较低,适用于非敏感信息的查询。POST更安全,适合传输敏感信息。

3、数据大小: GET请求通过URL传输数据,因此受URL长度限制,数据量较小。POST没有这个限制,可以传输大量数据。

4、幂等性: GET是幂等的,意味着多次执行相同的GET请求,资源的状态不会改变。而POST不是幂等的,它用于创建或更新资源。

什么是DNS泛解析,它有哪些用途?

DNS泛解析是DNS服务器解析记录的一种类型,允许对一个域名下的所有子域名进行统一解析到同一个IP地址。用途包括:

1、简化域名管理: 通过泛解析,无需为每个子域名单独设置A记录。

2、快速部署服务: 方便快速部署同一IP地址下的多个服务。

3、实现通配符子域名: 适用于需要大量动态生成子域名的应用,如多租户系统。

描述WebSocket如何实现全双工通信?

WebSocket通过建立一个持久的连接,实现客户端和服务器之间的全双工通信,即允许数据在两个方向上同时流动。实现全双工通信的过程包括:

1、握手: 客户端发起WebSocket连接请求,使用HTTP协议升级请求从HTTP协议切换到WebSocket协议。

2、连接建立: 服务器接受升级请求后,返回相应的HTTP响应,建立WebSocket连接。

3、数据交换: 一旦连接建立,客户端和服务器就可以在这个连接上双向发送数据,无需再次握手,直到其中一方主动关闭连接。

TCP如何确保数据包按序到达接收方?

TCP确保数据包按序到达接收方主要依赖于序列号机制:

  • 序列号: 每个TCP数据包都包含一个序列号,用于标识发送数据的顺序。接收方根据序列号对接收到的数据包进行排序,确保数据的正确顺序。
  • 确认应答(ACK): 接收方收到数据包后,会发送一个ACK给发送方,确认已经接收到的数据包序列号。这允许发送方知道哪些数据包已被成功接收。
  • 重传机制: 如果发送方没有在预期时间内收到对特定数据包的ACK,它会重新发送该数据包。这确保了数据包的到达和顺序性。

HTTP/2的服务器推送功能如何工作?

HTTP/2的服务器推送功能允许服务器主动向客户端发送资源,而无需客户端明确请求:

  • 预加载资源: 服务器可以预测客户端将需要的资源,并在发送请求页面的响应时一并发送这些资源,减少等待时间。
  • PUSH_PROMISE帧: 服务器通过发送PUSH_PROMISE帧给客户端,通知客户端它将发送哪些额外资源。这样客户端知道将接收到推送的资源,避免发起重复的请求。
  • 提高效率: 服务器推送减少了客户端的请求次数和整体的加载时间,提高了网页的加载速度和用户体验。

UDP如何支持多播通信?

UDP支持多播通信通过使用特定的多播IP地址和端口号实现:

  • 多播IP地址: 一个特定范围内的IP地址被指定用于多播,数据包发送到这个多播地址将被路由到加入该多播组的所有主机。
  • 加入多播组: 主机使用特定的系统调用或API加入一个多播组,表明它希望接收发送到该组地址的数据包。
  • 路由优化: 网络设备如路由器使用IGMP(Internet Group Management Protocol)协议来管理多播组成员资格和优化多播数据包的传输。

Socket中SO_REUSEADDR选项的作用是什么?

SO_REUSEADDR选项允许多个套接字绑定到同一端口,用于以下场景:

  • 快速重启: 允许服务器应用在没有完全关闭处于TIME_WAIT状态的套接字的情况下重启,提高端口的复用性。
  • 多个套接字监听相同端口: 在特定的应用中,可能需要多个进程或线程监听同一个端口接收不同的连接,SO_REUSEADDR使得这成为可能。

启用这个选项可以使得在同一端口上启动绑定操作更加灵活,特别是对于服务器应用的快速重启和负载分担非常有用。

如何理解TCP的拥塞控制机制?

TCP的拥塞控制机制是一种用来避免过度填充网络通信链路的技术。它通过动态调整数据传输速率来减少网络拥塞。TCP使用几种算法来实现拥塞控制,包括慢启动、拥塞避免、快速重传和快速恢复:

1、慢启动(Slow Start): 连接建立时,拥塞窗口(cwnd)从1或一个较小的值开始,每收到一个ACK,cwnd加倍。这个指数增长持续到cwnd达到慢启动阈值(ssthresh)。

2、拥塞避免(Congestion Avoidance): 当cwnd达到ssthresh后,进入拥塞避免阶段,cwnd线性增长,每经过一个往返时间(RTT),cwnd增加1。

3、快速重传(Fast Retransmit): 发送方在收到三个重复的ACK时,立即重传对应的数据包,而不是等待重传计时器超时。

4、快速恢复(Fast Recovery): 在快速重传后,ssthresh设置为当前cwnd的一半,cwnd设置为ssthresh加3*段的最大数据量(MSS),然后进入拥塞避免阶段。

通过这些机制,TCP能够在网络状态变化时动态调整传输速率,减少数据丢失,提高网络利用率。

HTTP协议中的幂等性是什么意思?

幂等性是HTTP协议中的一个重要概念,指一个操作执行一次和多次效果相同,不会因为执行多次而产生不同的效果。在HTTP方法中,GET、PUT、DELETE是幂等的,而POST通常不是幂等的:

  • GET:用于请求资源,不管执行多少次,资源的状态都不会改变。
  • PUT:用于上传资源,多次上传同一个资源,服务器上的状态是相同的。
  • DELETE:用于删除资源,删除一个资源多次和删除一次效果相同,即资源被删除。
  • POST:用于创建资源,每次请求可能会创建一个新的资源,因此不是幂等的。

理解幂等性对于设计RESTful API和处理网络请求重试机制非常重要,以确保系统的稳定性和可靠性。

描述UDP的可靠性机制如何实现?

虽然UDP本身是一个无连接的、不保证数据可靠性的协议,但应用层可以通过实现一些机制来增加可靠性:

  • 应用层确认和重传:发送方可以为每个UDP数据包设计一个超时重传机制,如果在指定时间内没有收到接收方的确认应答,就重传该数据包。
  • 序列号:在数据包中加入序列号,接收方可以根据序列号判断数据包是否丢失或重复,并按正确的顺序处理数据包。
  • 校验和:UDP头部包含校验和,用于检测数据在传输过程中的任何变化,确保数据完整性。接收方可以请求重传损坏的数据包。
  • 流量控制:通过控制发送速率,避免接收方处理不过来而导致的数据丢失。

通过这些机制,可以在UDP协议上构建更加可靠的数据传输服务,尽管这会增加复杂性和开销。

Socket编程中,select和poll的区别是什么?

select和poll都是IO多路复用的技术,用于监视多个文件描述符的状态变化。它们的主要区别在于效率和可扩展性:

select:

  • 有最大文件描述符数量的限制,默认情况下通常为1024。
  • 每次调用select时,都需要重新指定监听的文件描述符集合,因为调用会修改集合。
  • 使用位图来表示文件描述符集合,因此随着监控的文件描述符数量增加,效率会降低。

poll:

  • 没有最大文件描述符的限制,可以处理更多的连接。
  • 使用一个文件描述符数组作为参数,每个元素指定了所关心的事件和发生的事件,不需要每次调用时重置。
  • 由于使用的是数组而非位图,随着监控的文件描述符数量增加,性能不会显著下降。

poll提供了比select更好的可扩展性和灵活性,尤其是在需要监控大量文件描述符的应用中。


张洪亮


小林coding 配合飞书食用哦

小林coding

一.基础篇

2.1TCP/IP网络模型有哪几层 ?

2.2键入网址到网页显示,期间发生了什么?

2.3Linux系统是如何收发网络包的?

二、HTTP篇

3.1.HTTP常见面试题

3.2HTTP1.1如何优化

3.3HTTP RSA握手解析

3.4HTTPS ECDHE握手解析

HTTPS的加密过程

3.5HTTPS如何进行优化?

3.6HTTP/2牛逼在哪?

3.7.HTTP3强势来袭

3.8既然有HTTP协议,为什么还有RPC?

3.9既然有了HTTP协议,为什么还有WebSocket?

三、TCP篇

4.1TCP 三次握手与四次挥手面试题

4.2TCP 重传、滑动窗口、流量控制、拥塞控制

4.3 TCP 实战抓包分析

4.4TCP 半连接队列和全连接队列

4.5如何优化 TCP?

4.6如何理解是 TCP 面向字节流协议?

4.7为什么 TCP 每次建立连接时,初始化序列号都要不一样呢?

4.8SYN 报文什么时候情况下会被丢弃?

4.9已建立连接的TCP收到SYN会发生什么?

4.10四次挥手中收到乱序的 FIN 包会如何处理?

4.11在 TIME WAIT 状态的 TCP 连接,收到 SYN后会发生什么?

4.12TCP 连接,一端断电和进程崩溃有什么区别?

4.13拔掉网线后, 原本的 TCP 连接还存在吗?

4.14tcptwreuse 为什么默认是关闭的?

4.15HTTPS 中 TLS 和TCP 能同时握手吗?

4.16TCP Keepalive 和HTTP Keep-Alive 是一个东西吗?

4.17TCP 协议有什么缺陷?

4.18如何基于 UDP 协议实现可靠传输?

4.19TCP 和 UDP 可以使用同一个端口吗?

4.20服务端没有 listen客户端发起连接建立会发生什么?

4.21用了 TCP 协议,数据一定不会丢吗?

4.22TCP 四次挥手,可以变成三次吗?

4.23TCP 序列号和确认号是如何变化的?

四、IP篇

5.1IP基础知识全家桶

5.2ping的工作原理

5.3断网了,难道还能够ping通127.0.0.1吗?

五学习心得

JavaGuide

其他的地方补充的面经(牛客和微信公众号)

1. TCP和UDP区别,TCP的time_wait状态是什么;udp如何保证可靠,怎么实现,和TCP比性能如何

2.假设有两台服务器,怎么确定这两台服务器是否网络可通(不能用ping)

那假设A服务器开了8080端口,B服务器用什么命令去访问

了解滑动窗口吗

那你讲一下拥塞控制的方法

一个网页里一个图片链接,点开用了哪些协议

小林Coding TCP篇

服务器出现大量 TIME_WAIT 状态的原因有哪些?

首先要知道 TIME_WAIT 状态是主动关闭连接方才会出现的状态,所以如果服务器出现大量的 TIME_WAIT 状态的 TCP 连接,就是说明服务器主动断开了很多 TCP 连接。

问题来了,什么场景下服务端会主动断开连接呢?

  • 第一个场景:HTTP 没有使用长连接
  • 第二个场景:HTTP 长连接超时
  • 第三个场景:HTTP 长连接的请求数量达到上限

接下来,分别介绍下。

第一个场景:HTTP 没有使用长连接

我们先来看看 HTTP 长连接(Keep-Alive)机制是怎么开启的。

在 HTTP/1.0 中默认是关闭的,如果浏览器要开启 Keep-Alive,它必须在请求的 header 中添加:


Connection: Keep-Alive

然后当服务器收到请求,作出回应的时候,它也被添加到响应中 header 里:

Connection: Keep-Alive

这样做,TCP 连接就不会中断,而是保持连接。当客户端发送另一个请求时,它会使用同一个 TCP 连接。这一直继续到客户端或服务器端提出断开连接。

从 HTTP/1.1 开始, 就默认是开启了 Keep-Alive,现在大多数浏览器都默认是使用 HTTP/1.1,所以 Keep-Alive 都是默认打开的。一旦客户端和服务端达成协议,那么长连接就建立好了。

如果要关闭 HTTP Keep-Alive,需要在 HTTP 请求或者响应的 header 里添加 Connection:close 信息,也就是说,只要客户端和服务端任意一方的 HTTP header 中有 Connection:close 信息,那么就无法使用 HTTP 长连接的机制。

关闭 HTTP 长连接机制后,每次请求都要经历这样的过程:建立 TCP -> 请求资源 -> 响应资源 -> 释放连接,那么此方式就是 HTTP 短连接,如下图:

在前面我们知道,只要任意一方的 HTTP header 中有 Connection:close 信息,就无法使用 HTTP 长连接机制,这样在完成一次 HTTP 请求/处理后,就会关闭连接。

问题来了,这时候是客户端还是服务端主动关闭连接呢?

在 RFC 文档中,并没有明确由谁来关闭连接,请求和响应的双方都可以主动关闭 TCP 连接。

不过,根据大多数 Web 服务的实现,不管哪一方禁用了 HTTP Keep-Alive,都是由服务端主动关闭连接,那么此时服务端上就会出现 TIME_WAIT 状态的连接。

客户端禁用了 HTTP Keep-Alive,服务端开启 HTTP Keep-Alive,谁是主动关闭方?

当客户端禁用了 HTTP Keep-Alive,这时候 HTTP 请求的 header 就会有 Connection:close 信息,这时服务端在发完 HTTP 响应后,就会主动关闭连接。

为什么要这么设计呢?HTTP 是请求-响应模型,发起方一直是客户端,HTTP Keep-Alive 的初衷是为客户端后续的请求重用连接,如果我们在某次 HTTP 请求-响应模型中,请求的 header 定义了 connection:close 信息,那不再重用这个连接的时机就只有在服务端了,所以我们在 HTTP 请求-响应这个周期的「末端」关闭连接是合理的。

客户端开启了 HTTP Keep-Alive,服务端禁用了 HTTP Keep-Alive,谁是主动关闭方?

当客户端开启了 HTTP Keep-Alive,而服务端禁用了 HTTP Keep-Alive,这时服务端在发完 HTTP 响应后,服务端也会主动关闭连接。

为什么要这么设计呢?在服务端主动关闭连接的情况下,只要调用一次 close() 就可以释放连接,剩下的工作由内核 TCP 栈直接进行了处理,整个过程只有一次 syscall;如果是要求 客户端关闭,则服务端在写完最后一个 response 之后需要把这个 socket 放入 readable 队列,调用 select / epoll 去等待事件;然后调用一次 read() 才能知道连接已经被关闭,这其中是两次 syscall,多一次用户态程序被激活执行,而且 socket 保持时间也会更长。

因此,当服务端出现大量的 TIME_WAIT 状态连接的时候,可以排查下是否客户端和服务端都开启了 HTTP Keep-Alive,因为任意一方没有开启 HTTP Keep-Alive,都会导致服务端在处理完一个 HTTP 请求后,就主动关闭连接,此时服务端上就会出现大量的 TIME_WAIT 状态的连接。

针对这个场景下,解决的方式也很简单,让客户端和服务端都开启 HTTP Keep-Alive 机制。

第二个场景:HTTP 长连接超时

HTTP 长连接的特点是,只要任意一端没有明确提出断开连接,则保持 TCP 连接状态。

HTTP 长连接可以在同一个 TCP 连接上接收和发送多个 HTTP 请求/应答,避免了连接建立和释放的开销。

可能有的同学会问,如果使用了 HTTP 长连接,如果客户端完成一个 HTTP 请求后,就不再发起新的请求,此时这个 TCP 连接一直占用着不是挺浪费资源的吗?

对没错,所以为了避免资源浪费的情况,web 服务软件一般都会提供一个参数,用来指定 HTTP 长连接的超时时间,比如 nginx 提供的 keepalive_timeout 参数。

假设设置了 HTTP 长连接的超时时间是 60 秒,nginx 就会启动一个「定时器」,如果客户端在完后一个 HTTP 请求后,在 60 秒内都没有再发起新的请求,定时器的时间一到,nginx 就会触发回调函数来关闭该连接,那么此时服务端上就会出现 TIME_WAIT 状态的连接。

当服务端出现大量 TIME_WAIT 状态的连接时,如果现象是有大量的客户端建立完 TCP 连接后,很长一段时间没有发送数据,那么大概率就是因为 HTTP 长连接超时,导致服务端主动关闭连接,产生大量处于 TIME_WAIT 状态的连接。

可以往网络问题的方向排查,比如是否是因为网络问题,导致客户端发送的数据一直没有被服务端接收到,以至于 HTTP 长连接超时。

第三个场景:HTTP 长连接的请求数量达到上限

Web 服务端通常会有个参数,来定义一条 HTTP 长连接上最大能处理的请求数量,当超过最大限制时,就会主动关闭连接。

比如 nginx 的 keepalive_requests 这个参数,这个参数是指一个 HTTP 长连接建立之后,nginx 就会为这个连接设置一个计数器,记录这个 HTTP 长连接上已经接收并处理的客户端请求的数量。如果达到这个参数设置的最大值时,则 nginx 会主动关闭这个长连接,那么此时服务端上就会出现 TIME_WAIT 状态的连接。

keepalive_requests 参数的默认值是 100 ,意味着每个 HTTP 长连接最多只能跑 100 次请求,这个参数往往被大多数人忽略,因为当 QPS (每秒请求数) 不是很高时,默认值 100 凑合够用。

但是,对于一些 QPS 比较高的场景,比如超过 10000 QPS,甚至达到 30000 , 50000 甚至更高,如果 keepalive_requests 参数值是 100,这时候就 nginx 就会很频繁地关闭连接,那么此时服务端上就会出大量的 TIME_WAIT 状态。

针对这个场景下,解决的方式也很简单,调大 nginx 的 keepalive_requests 参数就行。

服务器出现大量 TIME_WAIT 状态的原因有哪些?

首先要知道 TIME_WAIT 状态是主动关闭连接方才会出现的状态,所以如果服务器出现大量的 TIME_WAIT 状态的 TCP 连接,就是说明服务器主动断开了很多 TCP 连接。

问题来了,什么场景下服务端会主动断开连接呢?

  • 第一个场景:HTTP 没有使用长连接
  • 第二个场景:HTTP 长连接超时
  • 第三个场景:HTTP 长连接的请求数量达到上限

接下来,分别介绍下。

第一个场景:HTTP 没有使用长连接

我们先来看看 HTTP 长连接(Keep-Alive)机制是怎么开启的。

在 HTTP/1.0 中默认是关闭的,如果浏览器要开启 Keep-Alive,它必须在请求的 header 中添加:

Connection: Keep-Alive

然后当服务器收到请求,作出回应的时候,它也被添加到响应中 header 里:

Connection: Keep-Alive

这样做,TCP 连接就不会中断,而是保持连接。当客户端发送另一个请求时,它会使用同一个 TCP 连接。这一直继续到客户端或服务器端提出断开连接。

从 HTTP/1.1 开始, 就默认是开启了 Keep-Alive,现在大多数浏览器都默认是使用 HTTP/1.1,所以 Keep-Alive 都是默认打开的。一旦客户端和服务端达成协议,那么长连接就建立好了。

如果要关闭 HTTP Keep-Alive,需要在 HTTP 请求或者响应的 header 里添加 Connection:close 信息,也就是说,只要客户端和服务端任意一方的 HTTP header 中有 Connection:close 信息,那么就无法使用 HTTP 长连接的机制。

关闭 HTTP 长连接机制后,每次请求都要经历这样的过程:建立 TCP -> 请求资源 -> 响应资源 -> 释放连接,那么此方式就是 HTTP 短连接,如下图:

在前面我们知道,只要任意一方的 HTTP header 中有 Connection:close 信息,就无法使用 HTTP 长连接机制,这样在完成一次 HTTP 请求/处理后,就会关闭连接。

问题来了,这时候是客户端还是服务端主动关闭连接呢?

在 RFC 文档中,并没有明确由谁来关闭连接,请求和响应的双方都可以主动关闭 TCP 连接。

不过,根据大多数 Web 服务的实现,不管哪一方禁用了 HTTP Keep-Alive,都是由服务端主动关闭连接,那么此时服务端上就会出现 TIME_WAIT 状态的连接。

客户端禁用了 HTTP Keep-Alive,服务端开启 HTTP Keep-Alive,谁是主动关闭方?

当客户端禁用了 HTTP Keep-Alive,这时候 HTTP 请求的 header 就会有 Connection:close 信息,这时服务端在发完 HTTP 响应后,就会主动关闭连接。

为什么要这么设计呢?HTTP 是请求-响应模型,发起方一直是客户端,HTTP Keep-Alive 的初衷是为客户端后续的请求重用连接,如果我们在某次 HTTP 请求-响应模型中,请求的 header 定义了 connection:close 信息,那不再重用这个连接的时机就只有在服务端了,所以我们在 HTTP 请求-响应这个周期的「末端」关闭连接是合理的。

客户端开启了 HTTP Keep-Alive,服务端禁用了 HTTP Keep-Alive,谁是主动关闭方?

当客户端开启了 HTTP Keep-Alive,而服务端禁用了 HTTP Keep-Alive,这时服务端在发完 HTTP 响应后,服务端也会主动关闭连接。

为什么要这么设计呢?在服务端主动关闭连接的情况下,只要调用一次 close() 就可以释放连接,剩下的工作由内核 TCP 栈直接进行了处理,整个过程只有一次 syscall;如果是要求 客户端关闭,则服务端在写完最后一个 response 之后需要把这个 socket 放入 readable 队列,调用 select / epoll 去等待事件;然后调用一次 read() 才能知道连接已经被关闭,这其中是两次 syscall,多一次用户态程序被激活执行,而且 socket 保持时间也会更长。

因此,当服务端出现大量的 TIME_WAIT 状态连接的时候,可以排查下是否客户端和服务端都开启了 HTTP Keep-Alive,因为任意一方没有开启 HTTP Keep-Alive,都会导致服务端在处理完一个 HTTP 请求后,就主动关闭连接,此时服务端上就会出现大量的 TIME_WAIT 状态的连接。

针对这个场景下,解决的方式也很简单,让客户端和服务端都开启 HTTP Keep-Alive 机制。

第二个场景:HTTP 长连接超时

HTTP 长连接的特点是,只要任意一端没有明确提出断开连接,则保持 TCP 连接状态。

HTTP 长连接可以在同一个 TCP 连接上接收和发送多个 HTTP 请求/应答,避免了连接建立和释放的开销。

可能有的同学会问,如果使用了 HTTP 长连接,如果客户端完成一个 HTTP 请求后,就不再发起新的请求,此时这个 TCP 连接一直占用着不是挺浪费资源的吗?

对没错,所以为了避免资源浪费的情况,web 服务软件一般都会提供一个参数,用来指定 HTTP 长连接的超时时间,比如 nginx 提供的 keepalive_timeout 参数。

假设设置了 HTTP 长连接的超时时间是 60 秒,nginx 就会启动一个「定时器」,如果客户端在完后一个 HTTP 请求后,在 60 秒内都没有再发起新的请求,定时器的时间一到,nginx 就会触发回调函数来关闭该连接,那么此时服务端上就会出现 TIME_WAIT 状态的连接。

当服务端出现大量 TIME_WAIT 状态的连接时,如果现象是有大量的客户端建立完 TCP 连接后,很长一段时间没有发送数据,那么大概率就是因为 HTTP 长连接超时,导致服务端主动关闭连接,产生大量处于 TIME_WAIT 状态的连接。

可以往网络问题的方向排查,比如是否是因为网络问题,导致客户端发送的数据一直没有被服务端接收到,以至于 HTTP 长连接超时。

第三个场景:HTTP 长连接的请求数量达到上限

Web 服务端通常会有个参数,来定义一条 HTTP 长连接上最大能处理的请求数量,当超过最大限制时,就会主动关闭连接。

比如 nginx 的 keepalive_requests 这个参数,这个参数是指一个 HTTP 长连接建立之后,nginx 就会为这个连接设置一个计数器,记录这个 HTTP 长连接上已经接收并处理的客户端请求的数量。如果达到这个参数设置的最大值时,则 nginx 会主动关闭这个长连接,那么此时服务端上就会出现 TIME_WAIT 状态的连接。

keepalive_requests 参数的默认值是 100 ,意味着每个 HTTP 长连接最多只能跑 100 次请求,这个参数往往被大多数人忽略,因为当 QPS (每秒请求数) 不是很高时,默认值 100 凑合够用。

但是,对于一些 QPS 比较高的场景,比如超过 10000 QPS,甚至达到 30000 , 50000 甚至更高,如果 keepalive_requests 参数值是 100,这时候就 nginx 就会很频繁地关闭连接,那么此时服务端上就会出大量的 TIME_WAIT 状态。

针对这个场景下,解决的方式也很简单,调大 nginx 的 keepalive_requests 参数就行。

服务器出现大量 CLOSE_WAIT 状态的原因有哪些?

CLOSE_WAIT 状态是「被动关闭方」才会有的状态,而且如果「被动关闭方」没有调用 close 函数关闭连接,那么就无法发出 FIN 报文,从而无法使得 CLOSE_WAIT 状态的连接转变为 LAST_ACK 状态。

所以,当服务端出现大量 CLOSE_WAIT 状态的连接的时候,说明服务端的程序没有调用 close 函数关闭连接。

那什么情况会导致服务端的程序没有调用 close 函数关闭连接?这时候通常需要排查代码。

我们先来分析一个普通的 TCP 服务端的流程:

  1. 创建服务端 socket,bind 绑定端口、listen 监听端口
  2. 将服务端 socket 注册到 epoll
  3. epoll_wait 等待连接到来,连接到来时,调用 accpet 获取已连接的 socket
  4. 将已连接的 socket 注册到 epoll
  5. epoll_wait 等待事件发生
  6. 对方连接关闭时,我方调用 close

可能导致服务端没有调用 close 函数的原因,如下。

第一个原因:第 2 步没有做,没有将服务端 socket 注册到 epoll,这样有新连接到来时,服务端没办法感知这个事件,也就无法获取到已连接的 socket,那服务端自然就没机会对 socket 调用 close 函数了。

不过这种原因发生的概率比较小,这种属于明显的代码逻辑 bug,在前期 read view 阶段就能发现的了。

第二个原因: 第 3 步没有做,有新连接到来时没有调用 accpet 获取该连接的 socket,导致当有大量的客户端主动断开了连接,而服务端没机会对这些 socket 调用 close 函数,从而导致服务端出现大量 CLOSE_WAIT 状态的连接。

发生这种情况可能是因为服务端在执行 accpet 函数之前,代码卡在某一个逻辑或者提前抛出了异常。

第三个原因:第 4 步没有做,通过 accpet 获取已连接的 socket 后,没有将其注册到 epoll,导致后续收到 FIN 报文的时候,服务端没办法感知这个事件,那服务端就没机会调用 close 函数了。

发生这种情况可能是因为服务端在将已连接的 socket 注册到 epoll 之前,代码卡在某一个逻辑或者提前抛出了异常。之前看到过别人解决 close_wait 问题的实践文章,感兴趣的可以看看:一次 Netty 代码不健壮导致的大量 CLOSE_WAIT 连接原因分析(opens new window)

第四个原因:第 6 步没有做,当发现客户端关闭连接后,服务端没有执行 close 函数,可能是因为代码漏处理,或者是在执行 close 函数之前,代码卡在某一个逻辑,比如发生死锁等等。

可以发现,当服务端出现大量 CLOSE_WAIT 状态的连接的时候,通常都是代码的问题,这时候我们需要针对具体的代码一步一步的进行排查和定位,主要分析的方向就是服务端为什么没有调用 close。

#如果已经建立了连接,但是客户端突然出现故障了怎么办?

客户端出现故障指的是客户端的主机发生了宕机,或者断电的场景。发生这种情况的时候,如果服务端一直不会发送数据给客户端,那么服务端是永远无法感知到客户端宕机这个事件的,也就是服务端的 TCP 连接将一直处于 ESTABLISH 状态,占用着系统资源。

为了避免这种情况,TCP 搞了个保活机制。这个机制的原理是这样的:

定义一个时间段,在这个时间段内,如果没有任何连接相关的活动,TCP 保活机制会开始作用,每隔一个时间间隔,发送一个探测报文,该探测报文包含的数据非常少,如果连续几个探测报文都没有得到响应,则认为当前的 TCP 连接已经死亡,系统内核将错误信息通知给上层应用程序。

在 Linux 内核可以有对应的参数可以设置保活时间、保活探测的次数、保活探测的时间间隔,以下都为默认值:

net.ipv4.tcp_keepalive_time=7200
net.ipv4.tcp_keepalive_intvl=75  
net.ipv4.tcp_keepalive_probes=9
  • tcp_keepalive_time=7200:表示保活时间是 7200 秒(2小时),也就 2 小时内如果没有任何连接相关的活动,则会启动保活机制
  • tcp_keepalive_intvl=75:表示每次检测间隔 75 秒;
  • tcp_keepalive_probes=9:表示检测 9 次无响应,认为对方是不可达的,从而中断本次的连接。

也就是说在 Linux 系统中,最少需要经过 2 小时 11 分 15 秒才可以发现一个「死亡」连接。

注意,应用程序若想使用 TCP 保活机制需要通过 socket 接口设置 SO_KEEPALIVE 选项才能够生效,如果没有设置,那么就无法使用 TCP 保活机制。

如果开启了 TCP 保活,需要考虑以下几种情况:

  • 第一种,对端程序是正常工作的。当 TCP 保活的探测报文发送给对端, 对端会正常响应,这样 TCP 保活时间会被重置,等待下一个 TCP 保活时间的到来。
  • 第二种,对端主机宕机并重启。当 TCP 保活的探测报文发送给对端后,对端是可以响应的,但由于没有该连接的有效信息,会产生一个 RST 报文,这样很快就会发现 TCP 连接已经被重置。
  • 第三种,是对端主机宕机(注意不是进程崩溃,进程崩溃后操作系统在回收进程资源的时候,会发送 FIN 报文,而主机宕机则是无法感知的,所以需要 TCP 保活机制来探测对方是不是发生了主机宕机),或对端由于其他原因导致报文不可达。当 TCP 保活的探测报文发送给对端后,石沉大海,没有响应,连续几次,达到保活探测次数后,TCP 会报告该 TCP 连接已经死亡。

TCP 保活的这个机制检测的时间是有点长,我们可以自己在应用层实现一个心跳机制。

比如,web 服务软件一般都会提供 keepalive_timeout 参数,用来指定 HTTP 长连接的超时时间。如果设置了 HTTP 长连接的超时时间是 60 秒,web 服务软件就会启动一个定时器,如果客户端在完成一个 HTTP 请求后,在 60 秒内都没有再发起新的请求,定时器的时间一到,就会触发回调函数来释放该连接。

#如果已经建立了连接,但是服务端的进程崩溃会发生什么?

TCP 的连接信息是由内核维护的,所以当服务端的进程崩溃后,内核需要回收该进程的所有 TCP 连接资源,于是内核会发送第一次挥手 FIN 报文,后续的挥手过程也都是在内核完成,并不需要进程的参与,所以即使服务端的进程退出了,还是能与客户端完成 TCP 四次挥手的过程。

我自己做了个实验,使用 kill -9 来模拟进程崩溃的情况,发现在 kill 掉进程后,服务端会发送 FIN 报文,与客户端进行四次挥手。

TCP 连接,一端断电和进程崩溃有什么区别?

拔掉网线后, 原本的 TCP 连接还存在吗?

服务端没有 listen,客户端发起连接建立,会发生什么?

TCP 和 UDP 可以使用同一个端口吗?

关于上面问题点详细链接

https://xiaolincoding.com/network/3_tcp/port.html

https://xiaolincoding.com/network/3_tcp/port.html#%E6%80%BB%E7%BB%93

如何理解TCP是面向字节流的服务?

SYN 报文什么时候情况下会被丢弃?

已建立连接的TCP,收到SYN会发生什么

如何关闭一个 TCP 连接?

四次挥手中收到乱序的 FIN 包会如何处理?

在 TIME_WAIT 状态的 TCP 连接,收到 SYN 后会发生什么?

被问到既然打开 net.ipv4.tcp_tw_reuse 参数可以快速复用处于 TIME_WAIT 状态的 TCP 连接,那为什么 Linux 默认是关闭状态呢?

HTTPS 中 TLS 和 TCP 能同时握手吗?

TCP Keepalive 和 HTTP Keep-Alive 是一个东西吗?

TCP协议有什么缺陷

如何基于 UDP 协议实现可靠传输?

服务端没有 listen,客户端发起连接建立,会发生什么?

没有 accept,能建立 TCP 连接吗?

用了 TCP 协议,数据一定不会丢吗?

TCP 四次挥手,可以变成三次吗?

4.23 TCP 序列号和确认号是如何变化的?

小林Coding IP

ping的工作原理 这个小林Coding确实没有

断网了,还能 ping 通 127.0.0.1 吗?

好了小林的补充只有才TCP才有!

林秋地

1. OSI 的七层模型分别是?各自的功能是什么?

2. 为什么需要三次握手?两次不行?

3. 为什么需要四次挥手?三次不行?

4. TCP与UDP有哪些区别?各自应用场景?

5. HTTP1.0,1.1,2.0 的版本区别

6. POST和GET有哪些区别?各自应用场景?

7. HTTP 哪些常用的状态码及使用场景?

8. HTTP状态码301和302的区别,都有哪些用途?

9. 在交互过程中如果数据传送完了,还不想断开连接怎么办,怎么维持?

10. HTTP 如何实现长连接?在什么时候会超时?

11. TCP 如何保证有效传输及拥塞控制原理

12. IP地址有哪些分类?

13. GET请求中URL编码的意义

14. 什么是SQL 注入?举个例子?

15. 谈一谈 XSS 攻击,举个例子?

16. 讲一下网络五层模型,每一层的职责?

17. 简单说下 HTTPS 和 HTTP 的区别

18. 对称加密与非对称加密的区别

19. 简单说下每一层对应的网络协议有哪些?

20. ARP 协议的工作原理?

21. TCP 的主要特点是什么?

22. UDP 的主要特点是什么?

23. TCP 和 UDP 分别对应的常见应用层协议有哪些?

24. 为什么 TIME-WAIT 状态必须等待 2MSL 的时间呢?

25. 保活计时器的作用?

26. TCP 协议是如何保证可靠传输的?

27. 谈谈你对停止等待协议的理解?

28. 谈谈你对 ARQ 协议的理解?

29. 谈谈你对滑动窗口的了解?

30. 谈下你对流量控制的理解?

31. 谈下你对 TCP 拥塞控制的理解?使用了哪些算法?

32. 什么是粘包?

33. TCP 黏包是怎么产生的?

34. 怎么解决拆包和粘包?

35. forward 和 redirect 的区别?

36. HTTP 方法有哪些?

37. 在浏览器中输入 URL 地址到显示主页的过程?

38. DNS 的解析过程?

39. 谈谈你对域名缓存的了解?

40. 谈下你对 HTTP 长连接和短连接的理解?分别应用于哪些场景?

41. HTTPS 的工作过程?

42. HTTP 和 HTTPS 的区别?

43. HTTPS 的优缺点?

44. 什么是数字签名?

45. 什么是数字证书?

46. Cookie 和 Session 有什么区别?

47. UDP 如何实现可靠传输?

48. Keep-Alive 和非 Keep-Alive 有什么区别?

49. HTTP 长连接短连接使用场景是什么

50. DNS 为什么用 UDP

51. 简单说下怎么实现 DNS 劫持

52. URI和 URL之间的区别

53. TIME_WAIT 状态会导致什么问题,怎么解决

54. 有很多 TIME-WAIT 状态如何解决

55. 简单说下 SYN FLOOD 是什么

56. ICMP 有哪些应用?

57. TCP 最大连接数限制

58. IP地址和MAC地址有什么区别?各自的用处?

59. IPV4 地址不够如何解决

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值