面试八股
目录
TCP三次握手,每一次都发送了什么?
- 第一次握手:客户端向服务器发送一个SYN(同步序列编号)报文,告诉服务器它希望建立连接。这个报文包含一个客户端的初始序列号(ISNc),用于同步序列号。
- 第二次握手:服务器接收到客户端的SYN报文后,需要确认客户端的SYN。服务器发回一个SYN-ACK(确认)报文,其中ACK(确认)部分确认了客户端的初始序列号(即ACK = ISNc + 1),同时SYN部分包含服务器的初始序列号(ISNs)。
- 第三次握手:客户端收到服务器的SYN-ACK报文后,会发送一个ACK报文给服务器,其中包含的确认号是服务器的初始序列号加一(即ACK = ISNs + 1),表明客户端已经接收到了服务器的SYN报文,同时服务器也确认了客户端的ACK报文。
讲一下TCP四次挥手中,TIME_WAIT是干嘛的?2MSL是干嘛的?TIME_WAIT过多怎么解决?
TIME_WAIT
- 作用:
TIME_WAIT状态主要有两个目的:- 确保最后一个确认报文能够到达:如果服务器端最后发送的确认(ACK)报文丢失,客户端处于
TIME_WAIT状态可以重新发送这个确认报文。 - 等待足够的时间以确保所有旧的数据包在网络中消失:这样做是为了防止这些旧数据包在新的同样的端口号连接中被误认为是新数据。
- 确保最后一个确认报文能够到达:如果服务器端最后发送的确认(ACK)报文丢失,客户端处于
2MSL(Maximum Segment Lifetime)
- 定义:
2MSL是指报文最大生存时间的两倍。这是TIME_WAIT状态持续的时间。 - 作用:这段时间足够让网络中所有的数据包都因超时而消失,从而清理出所有可能混淆新旧连接的旧数据包。这就确保了新的连接不会接收到旧连接的数据包。
解决TIME_WAIT过多的问题
TIME_WAIT状态过多可能导致服务器资源被过度占用,从而影响新连接的建立。可以采取以下几种方法来解决或减轻这个问题:
- 调整内核参数:在某些操作系统中,可以调整TCP参数来缩短
TIME_WAIT的持续时间或改变端口的使用策略。 - 启用端口复用:设置
SO_REUSEADDR或SO_REUSEPORT选项允许在TIME_WAIT状态的端口被新的连接复用。 - 负载均衡:通过在多台服务器间分散连接请求,可以减轻单一服务器上的端口占用问题。
客户端服务器同时请求断开连接怎么办?
当客户端和服务器几乎同时请求断开连接时,每一方都按照TCP协议的规定发送FIN报文来请求关闭连接,并响应对方的FIN报文以确认关闭请求。即便双方同时发起断开请求,TCP协议通过交换FIN和ACK报文确保连接的双向顺利关闭。
这个过程表现为:
- 双方各自发送FIN:客户端和服务器都发送FIN报文,请求关闭自己这一端的连接。
- 双方各自回应ACK:每一方在接收到对方的FIN报文后,发送ACK报文作为回应,确认已经接收到对方的终止请求。
TCP滑动窗口是干嘛的?
我们都知道 TCP 是每发送一个数据,都要进行一次确认应答。当上一个数据包收到了应答了, 再发送下一个。
这样的传输方式有一个缺点:数据包的往返时间越长,通信的效率就越低。
窗口大小就是指无需等待确认应答,而可以继续发送数据的最大值。
窗口的实现实际上是操作系统开辟的一个缓存空间,发送方主机在等到确认应答返回之前,必须在缓冲区中保留已发送的数据。如果按期收到确认应答,此时数据就可以从缓存区清除。
滑动窗口的作用
- 流量控制:滑动窗口允许接收方控制发送方的发送速度,确保接收方能够来得及处理接收到的数据。接收方通过指定窗口大小来告诉发送方它能够接受的最大未确认数据量。
- 确保数据顺序:通过滑动窗口机制,TCP保证数据包的顺序性。发送方需要等待接收方对已发送数据的确认,才能继续发送新的数据段。
- 拥塞控制:滑动窗口还用于感知网络条件,如网络拥塞。当网络拥塞时,滑动窗口会减小,减缓发送速度;当网络状况良好时,窗口大小会增加,加快发送速度。
工作原理
- 窗口大小:窗口大小定义了在等待确认的情况下发送方可以发送的最大数据量。这个大小可以动态调整,根据接收方的接收能力和网络条件进行变化。
- 窗口滑动:当发送方收到来自接收方的确认(ACK)时,窗口会向前滑动,允许发送方发送更多的数据。如果ACK确认了多个数据包,窗口滑动的距离会更大。
数据包到了网卡缓冲区,如何到的应用进程,说一下?
1. 数据包接收
- 物理接收:当数据包通过物理媒介(如以太网)到达网卡时,网卡的硬件首先将数据包捕获并存储在网卡的硬件缓冲区中。
2. 中断和驱动处理
- 生成中断:数据包到达后,网卡会生成一个中断信号通知CPU有新数据到达。这个中断使得CPU暂停当前的任务,开始处理网络数据包。
- 驱动程序介入:操作系统的网络驱动程序响应中断,从网卡的缓冲区读取数据包。驱动程序可能会对数据包进行初步的处理,如检查错误、去除数据链路层的帧头等。
3. 操作系统处理
- 协议栈处理:数据包被传递到操作系统的网络协议栈。在这里,数据包按照网络层(IP)、传输层(TCP/UDP)等顺序进行处理。例如,IP层会处理路由和分片,而TCP层会处理数据重组、流控制等。
- 缓冲区管理:处理后的数据被存储在操作系统为每个套接字维护的缓冲区中。这些缓冲区用于暂存从网络接收的数据,直到应用程序准备好读取它们。
4. 应用程序获取数据
- 数据请求:应用程序通过系统调用(如read或recv)请求读取网络数据。这些调用让应用程序从操作系统的缓冲区中提取数据。
- 数据传递:操作系统将缓冲区中的数据传递给应用程序。应用程序在得到数据后,可以开始进行数据的进一步处理和响应。
TCP双方建立连接的API是什么,都做了什么?
服务器端
- 创建套接字:
- API:
socket() - 作用:创建一个套接字,指定使用TCP协议(通常是
SOCK_STREAM类型和AF_INET或AF_INET6协议族)。
- API:
- 绑定套接字:
- API:
bind() - 作用:将套接字与特定的IP地址和端口号关联。这一步是在服务器上进行,以便客户端可以向该地址和端口发起连接请求。
- API:
- 监听连接:
- API:
listen() - 作用:使得套接字变为被动模式,开始监听来自客户端的连接请求。可以设置监听队列的大小,决定同时能够接受多少个连接请求。
- API:
- 接受连接:
- API:
accept() - 作用:阻塞当前进程,直到客户端连接请求到来。当收到请求后,返回一个新的套接字,专门用于与请求的客户端通信。
- API:
客户端
- 创建套接字:
- 同服务器端,使用
socket()创建套接字。
- 同服务器端,使用
- 发起连接:
- API:
connect() - 作用:向服务器发起连接请求,需要指定服务器的IP地址和端口号。如果连接成功,客户端的套接字就准备好与服务器进行数据交换。
- API:
TCP四次挥手可以变成三次吗?
TCP是一个全双工的协议,意味着数据传输是独立的。客户端和服务器都需要单独地关闭各自的发送方向。第一个FIN和第一个ACK是关闭从客户端到服务器的方向,而第二个FIN和第二个ACK是关闭从服务器到客户端的方向。
如果被动关闭方没有数据需要发送,并且开启了TCP 延迟确认机制,那么第二次和第三次挥手就会合并传输,四次挥手变成三次挥手。
Linux查看多少个连接是已建立的?
使用 netstat 命令
netstat是一个非常传统的网络工具,用于显示网络连接、路由表、接口统计等信息。要查看已建立的TCP连接,可以使用以下命令:
bash复制代码
netstat -tnp | grep ESTABLISHED
这里的选项说明如下:
t表示仅显示TCP连接。n表示显示数字的IP地址和端口号,而不是尝试解析为域名。p表示显示关联的进程ID和程序名。
使用 grep ESTABLISHED 是为了筛选出状态为“ESTABLISHED”的连接,即已经完全建立的TCP连接。
讲一下字节序?
大端序(Big-Endian)
在大端序中,多字节数据的最高有效字节(MSB)存储在最低的内存地址,而最低有效字节(LSB)存储在最高的内存地址。换句话说,数据的第一个字节是数的最高有效字节。
举例:假设有一个16位整数0x1234存储在地址0x00和0x01上:
- 在地址
0x00(较低的地址)存储0x12 - 在地址
0x01(较高的地址)存储0x34
小端序(Little-Endian)
在小端序中,多字节数据的最低有效字节(LSB)存储在最低的内存地址,而最高有效字节(MSB)存储在最高的内存地址。换句话说,数据的第一个字节是数的最低有效字节。
举例:使用同样的16位整数0x1234存储在地址0x00和0x01上:
- 在地址
0x00(较低的地址)存储0x34 - 在地址
0x01(较高的地址)存储0x12
讲一下网络序和主机序?
网络字节序是一种数据在网络上传输时采用的字节序标准,也称为大端序(Big-Endian)。主机字节序是计算机内部处理和存储数据的格式,这可以是大端序或小端序,具体取决于处理器的架构。例如,大多数x86架构的计算机采用小端序存储数据。
转换重要性
由于不同的计算机系统可能使用不同的字节序,为了保证数据在网络上传输时的一致性和正确解析,通常需要在发送数据前将主机字节序转换为网络字节序,接收时再转换回来。这一过程通常由下列转换函数处理:
htonl()(Host TO Network Long): 将主机字节序的长整型数据转换为网络字节序。htons()(Host TO Network Short): 将主机字节序的短整型数据转换为网络字节序。ntohl()(Network TO Host Long): 将网络字节序的长整型数据转换为主机字节序。ntohs()(Network TO Host Short): 将网络字节序的短整型数据转换为主机字节序。
Select/Poll/Epoll?
select是最早的I/O多路复用机制,适用于几乎所有的Unix系统。
select使用位图来表示文件描述符集合,因此受限于最大文件描述符数(通常是1024/2048)。 select的性能会随着文件描述符数量的增加下降,因为每次调用都需要线性扫描整个文件描述符集合。 poll是select的改进版,解决了select的一些限制。poll使用链表来管理文件描述符,因此不受文件描述符数量的限制。 poll的性能也会随着文件描述符数量的增加而下降,与select类似,。 epoll是Linux特有的I/O多路复用机制,专为大规模文件描述符集合设计 epoll使用事件通知机制,不需要线性扫描文件描述符集合,性能优越。 epoll水平触发(Level-Triggered)和边缘触发(Edge-Triggered),提供了更灵活的使用方式。 epoll注册的文件描述符集合是持久的,不需要每次调用都传递。
| 特性 | select | poll | epoll |
|---|---|---|---|
| 文件描述符限制 | 有限制 | 无限制 | 无限制 |
| 性能 | 随文件描述符数量线性下降 | 随文件描述符数量线性下降 | 高效(事件通知机制) |
| 触发模式 | 水平触发 | 水平触发 | 水平触发和边缘触发 |
| 系统支持 | 所有Unix系统 | 大多数Unix系统 | Linux |
| API复杂度 | 简单 | 中等 | 复杂 |
Epoll的接口与实现?
epoll主要提供三个系统调用接口:
epoll_create或epoll_create1- 用于创建一个
epoll实例。 - 返回一个
epoll文件描述符。
int epoll_create(int size); int epoll_create1(int flags);- 用于创建一个
epoll_ctl- 用于控制
epoll实例,注册、修改或删除感兴趣的文件描述符事件。
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);epfd:epoll文件描述符。op:操作类型,取值为EPOLL_CTL_ADD、EPOLL_CTL_MOD、EPOLL_CTL_DEL。fd:需要监控的文件描述符。event:描述事件类型的epoll_event结构体指针。
- 用于控制
epoll_wait- 等待事件的发生。
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);epfd:epoll文件描述符。events:用于接收事件的数组。maxevents:数组的最大长度。timeout:等待的超时时间(毫秒)。
网卡接收到一个数据包,怎么判断是否是自己的呢?
网卡硬件首先检查数据包的目标MAC地址。网卡通常会有一个硬件过滤器,用于快速判断数据包是否应该被接收。这一过程在网卡驱动程序将数据包传递给操作系统之前完成。
一旦数据包通过了网卡硬件过滤器,数据包被传递到操作系统的网络协议栈进行进一步处理。
栈里面除了局部变量,函数参数和返回值,还有什么?
保存的寄存器(Saved Registers)、旧的帧指针(Old Frame Pointer / Base Pointer)、异常处理数据(Exception Handling Data)。
X86系统有哪些寄存器?
通用寄存器、段寄存器、指令指针寄存器、标志寄存器、控制寄存器、扩展寄存器、SIMD寄存器
$10^9$个数据,找出前100个?
- 构建一个大小为100的最小堆:初始化堆,存储前100个数据。
- 遍历剩余的数据:对于每个新的数据,如果它大于堆顶元素(最小堆的最小值),则将堆顶元素替换为该数据并调整堆。
- 完成遍历后,堆中保存的即为前100个最大值。