一、Posix API是什么
POSIX API(Portable Operating System Interface API)是一组可移植的操作系统接口,用于在不同的UNIX类操作系统之间实现更好的兼容性。该API定义了一系列标准函数和常量,以及许多其他规范,包括文件系统层次结构、进程控制、信号处理、线程管理、内存管理等。POSIX API使得开发人员能够编写具有较高可移植性的应用程序。
二、网络协议栈
1. TCP头部
字段 | 长度(字节) | 位数 | 描述 |
---|---|---|---|
源端口 | 2 | 16 | 标识发送方的应用程序端口号 |
目标端口 | 2 | 16 | 标识接收方的应用程序端口号 |
序列号 | 4 | 32 | 用于保证数据传输的可靠性,标识数据段的顺序 |
确认号 | 4 | 32 | 用于应答接收到的数据段,确认下一个期望接收的序列号 |
头部长度 | 4 | 4 | 指定TCP头部长度和包含的选项长度 |
保留位 | 6 | 6 | 保留位必须为0 |
控制位 | 6 | 6 | TCP控制位,如URG、ACK、PSH、RST、SYN和FIN |
窗口大小 | 2 | 16 | 定义对方可以发送多少数据而不会造成拥塞 |
校验和 | 2 | 16 | 计算TCP头部和数据的校验和 |
紧急指针 | 2 | 16 | 用于指示紧急数据的位置 |
选项 | 可变 | 可变 | 提供一些高级功能,例如最大分段大小、时间戳等 |
0 15 16 31
+---------------------------+------------------------+
| 源端口 | 目的端口 |
+---------------------------+------------------------+
| 序列号 |
+----------------------------------------------------+
| 确认号(如果A标志设置则存在) |
+---------------------------+------------------------+
| 数据偏移/长度 | 保留 | 控制位 |
+---------------------------+------------------------+
| 窗口大小 |
+---------------------------+------------------------+
| 校验和(如果需要则存在) |
+---------------------------+------------------------+
| 紧急指针(如果URG标志设置则存在) |
+---------------------------+------------------------+
| 选项(可选) |
+---------------------------+------------------------+
2. UDP报文
字段 | 位数 | 描述 |
---|---|---|
源端口号 | 16 | 发送端口号 |
目标端口号 | 16 | 接收端口号 |
长度 | 16 | UDP数据报长度(以字节为单位),包括UDP头部和数据部分 |
校验和 | 16 | UDP数据报校验和,由发送方计算并由接收方验证 |
+------+------+-------+-------+------------------------------+
| UDP头部 | 数据部分 |
+-----------+------------+-------+----------+----------------+
| 源端口号 | 目标端口号 | 长度 | 检验和 | 数据部分 |
+-----------+------------+-------+----------+----------------+
|<----------------------------UDP报文------------------------>|
3. IP协议
字段名称 | 长度(单位:bit) | 描述 |
---|---|---|
版本 | 4 | IP协议的版本号 |
头部长度 | 4 | IP头部的长度,以32位字为单位 |
区分服务 | 8 | 对IP数据报的处理方式进行分类和标记 |
总长度 | 16 | IP数据报总长度,包括头部和数据 |
标识 | 16 | 标识唯一地标志一个数据报,用于分片和重组 |
标志 | 3 | 用于控制分片,如不分片、分片或最后一片 |
分片偏移 | 13 | 用于确定分片相对于原始数据报开始的位置 |
生存时间 | 8 | IP数据报在网络中可通过的最大网段数 |
协议 | 8 | 标识数据报中的上层协议,如TCP、UDP等 |
头部校验和 | 16 | 对IP头部进行完整性检查的校验和 |
源地址 | 32 | 发送方的IP地址 |
目标地址 | 32 | 接收方的IP地址 |
选项 | 可变 | 可选字段,用于提供额外的信息 |
数据 | 可变 | 实际传输的数据 |
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| IHL |Type of Service| Total Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identification |Flags| Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Time to Live | Protocol | Header Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Destination Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
三、协议栈常见问题
1. TCP三次握手过程
TCP三次握手是指在建立一个TCP连接时,客户端和服务器之间发送的三个不同的数据包序列。
第一次:客户端向服务器发送请求连接的数据包(SYN)。
第二次:服务器收到客户端的请求后,回复一个确认收到请求的数据包(ACK)和自己的请求连接的数据包(SYN)。
第三次:客户端收到服务器的回复后,回复一个确认收到服务器请求连接的数据包(ACK),此时连接建立成功。
2. TCP四次挥手过程
第一次:关闭方发送一个FIN报文,请求关闭连接
第二次:对方接收到FIN报文后,回复一个ACK报文确认收到关闭请求,并进入到CLOSE_WAIT状态,表示准备关闭连接
第三次:对方发送一个FIN报文,表示自己也准备关闭连接
第四次:关闭方接收到FIN报文后,回复一个ACK报文确认收到关闭请求,并进入TIME_WAIT状态,等待可能出现的延迟报文。对方接收到ACK报文后,就可以关闭连接了
整个过程中,需要注意的是,每个报文都要等待对方的确认才能进行下一步操作,确保数据传输的可靠性。同时,最后一次挥手结束后,还需要等待一段时间(通常为两倍的最大报文段生存时间),以确保对方已经接收到所有数据,避免出现不必要的重传。
3. 为什么建立连接需要三次握手,而断开连接需要四次握手
建立连接需要三次握手是因为在TCP协议中,双方要确保对方能够收到自己发送的数据,在建立连接时需要进行确认
断开连接需要四次握手是因为TCP是全双工通信,当一方要关闭连接时,需要告诉对方自己没有数据要发送了,同时等待对方的确认,然后再等待对方也关闭连接
4. TIME_WAIT状态持续时间及原因
TIME_WAIT状态通常持续2倍的MSL(Maximum Segment Lifetime),即在TCP协议中,一个数据包最长能存活多久。在Linux系统中,这个默认值是60秒,所以TIME_WAIT状态一般持续120秒。
TIME_WAIT状态的原因是用于保证网络上所有的报文都被接收方成功接收并处理完成,防止之前发送的ACK丢失等问题导致后续出现的连接请求无法到达。
其主要目的有:
- 确认对端收到断开连接的请求
- 防止“活动的关闭”(Active Close)过程中重复使用相同的端口号
- 处理网络延迟和乱序报文导致的数据丢失和错误
TIME_WAIT状态的存在会占用一定的资源,如内存和CPU资源,但是这种情况下的消耗是相对比较小的。如果TIME_WAIT状态持续时间太长,可能会影响系统的性能表现
5. 超时重传和快速重传
超时重传和快速重传都是TCP协议中的重传机制。
超时重传是指当发送方发送数据后,等待一段时间(称为超时时间),如果未收到确认应答,就会重新发送数据。这种重传机制适用于网络状况不稳定的情况下,但如果超时时间设置过长将导致网络传输速度变慢
快速重传是指当接收方收到一个不连续的数据报时,发出重复ACK表示已经收到第二个数据包之前所有数据包。而发送方在收到3个重复ACK时,会立即重传未确认的数据包,而不需要等待超时时间。这种重传机制可以避免超时时间设置过长导致网络传输速度变慢的问题,加快了数据传输的速度
6. TCP头部有哪些字段
- 源端口号(16位):标识发送方应用程序的端口号。
- 目的端口号(16位):标识接收方应用程序的端口号。
- 序列号(32位):确定TCP报文段中第一个数据字节在整个数据流中的位置,也就是TCP序列号。
- 确认号(32位):期望收到对方下一个报文段的第一个数据字节的序列号,也就是TCP确认号。
- 数据偏移(4位):指明TCP头部长度,以4字节为单位。最小值为5(不包括可选字段),最大值为15(包括所有可选字段)。
- 保留(6位):保留位,未使用。
- 控制位(6位):用于控制TCP连接的建立、维持和释放。包括URG、ACK、PSH、RST、SYN、FIN六种控制位。
- 窗口大小(16位):指示接收方还可以接收多少字节的数据,也就是TCP窗口大小。
- 校验和(16位):用于检测TCP头部和数据的传输错误。
- 紧急指针(16位):提供紧急数据的位置,只有当URG标志被设置时才有效。
- 选项(可变长度):提供一些额外的TCP头部信息,如最大报文长度、时间戳等。选项字段的长度是可变的,可以为0字节或多个字节。
7. TCP在listen时的参数backlog的意义
TCP在listen时的参数backlog表示系统中未完成连接队列的最大长度。具体来说,当TCP服务器调用listen函数后,它将维护两个队列:
- 已完成连接队列
- 未完成连接队列
已完成连接队列包含已经建立连接并等待服务器接受的客户端连接,而未完成连接队列包含已经收到SYN报文段但还没有完成三次握手的客户端连接。
backlog参数控制未完成连接队列的最大长度。如果未完成连接队列已满,服务器将不再接受新的连接请求,直到队列中有空间。因此,backlog的值应该根据服务器预期的负载进行设置。如果backlog设置得太小,可能导致连接请求被拒绝;如果设置得太大,可能会占用过多的内存资源
backlog参数的意义是控制未完成连接队列的大小,以确保服务器可以处理尽可能多的连接请求,并避免拒绝服务或内存资源耗尽等问题。
8. Accept发生在三次握手的哪一步
Accept这个词一般是在TCP连接建立完成之后使用的,不会发生在三次握手的任何一步
9. 三次握手过程中有哪些不安全性
- SYN Flood攻击:攻击者可以发送大量的SYN请求,使服务端无法处理正常请求。
- IP欺骗:攻击者可以伪造源IP地址发送SYN请求,从而欺骗服务端。
- 重放攻击:攻击者可以通过截获并篡改一个旧的三次握手过程来进行攻击,从而绕过服务端的安全措施。
- 中间人攻击:攻击者可以在通信过程中拦截并篡改数据,从而达到非法获取信息或者干扰通信的目的。
10. TCP与UDP的区别
- 连接方式:TCP是面向连接的协议,传输前需要进行三次握手建立连接,传输完成后还需要四次挥手关闭连接;而UDP是无连接的协议,每个数据包都独立发送,不需要建立连接。
- 传输可靠性:TCP保证数据传输的可靠性,通过序列号、确认应答等机制确保数据准确无误地传输到目的地;而UDP不保证数据传输的可靠性,可能会丢失数据包或者重复传输。
- 数据传输效率:UDP在数据传输效率上优于TCP,因为它没有建立连接和数据校验的额外开销,并且可以通过广播和多播实现高效的数据传输。
- 流量控制:TCP支持流量控制,可以根据网络情况进行拥塞控制,使得数据传输更加稳定;而UDP没有流量控制机制,容易导致网络拥塞。
- 应用场景:TCP适合对传输可靠性要求较高的应用场景,如文件传输、电子邮件传输等;而UDP适合对传输速度要求较高、数据传输可靠性要求较低的应用场景,如音视频传输、游戏等。
推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家:
Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,立即学习