一、TCP协议基础特点
TCP(Transmission Control Protocol)传输控制协议
-
面向连接:通信之前必须建立连接,通信结束要断开连接;
-
面向字节流:把数据当成一串字节流,没有报文边界;
-
可靠传输:通过三次握手、应答确认、超时重传、滑动窗口等机制,保证数据无丢失、无重复、按序到达;
-
协议机制复杂,相比UDP开销更大,实时性弱于UDP。
适用场景:网页、文件传输、MQTT;不适合直播、游戏这类追求低延迟可容忍少量丢包场景。
二、TCP三次握手(建立连接)
客户端主动发起连接,三次握手目的:同步双方初始序列号,确认双方收发能力正常。
- 第一次握手:客户端发送SYN报文,携带客户端初始序列号seq=x,客户端进入SYN_SENT状态。
SYN标志位=1,表示请求建立连接。
-
第二次握手:服务端收到SYN,回复SYN+ACK报文;ACK确认号ack=x+1,同时携带服务端自己的初始序列号seq=y;服务端进入SYN_RCVD状态。
-
第三次握手:客户端收到SYN+ACK,回复ACK确认报文,确认号ack=y+1。客户端、服务端都进入ESTABLISHED(连接建立完成状态),之后就可以收发业务数据。
思考:为什么不能两次握手?
防止网络中滞留的旧无效连接报文到达服务器,服务器单方面建立无效连接,浪费服务器资源。
三、TCP四次挥手(断开连接)
TCP连接是全双工,两边可以独立关闭自己发送方向,因此断开需要四次。主动关闭方一般是客户端。
- 第一次挥手:客户端发送FIN报文,表示客户端不再发送数据,进入FIN_WAIT_1。
FIN标志位=1,代表请求关闭连接。
-
第二次挥手:服务端回复ACK确认FIN报文,客户端收到ACK进入FIN_WAIT_2。此时客户端不再发数据,但是服务端仍然可以继续向客户端发送剩余数据。
-
第三次挥手:当服务端业务数据全部发送完毕,服务端发送FIN报文,服务端进入LAST_ACK。
-
第四次挥手:客户端回复ACK确认FIN报文;客户端进入TIME_WAIT(等待2MSL);服务端收到ACK直接进入CLOSED;客户端等待2MSL时间过后,也进入CLOSED,连接彻底释放。
TIMEWAIT作用:
-
保证对方可以收到自己最后的ACK报文;
-
等待网络中该连接残留的旧数据包全部过期消失,避免干扰下一次新连接。
四、TCP报文头部解析
TCP头部固定20字节,可扩展选项最多60字节。
|----------------|---------------------------------|
| 字段 | 说明 |
| 源端口 (2 字节) | 发送方进程端口 |
| 目的端口 (2 字节) | 接收方进程端口 |
| 序列号 seq (4 字节) | 本报文段第一个字节数据编号 |
| 确认号 ack (4 字节) | 期望收到下一字节的编号;ack = 上一次收到最后字节 + 1 |
| 数据偏移 (4bit) | TCP 头部长度,单位 4 字节 |
| 保留位 (6bit) | 保留,默认 0 |
| 6 个标志位 | URG、ACK、PSH、RST、SYN、FIN |
| 窗口大小 (2 字节) | 流量控制,接收缓冲区剩余容量 |
| 校验和 (2 字节) | 校验报文完整性 |
| 紧急指针 (2 字节) | URG 有效时,标记紧急数据偏移 |
| 选项 | MSS、窗口扩大、时间戳等,可选 |
六大标志位含义
-
SYN:请求建立连接,三次握手使用;
-
ACK:确认报文,绝大多数数据包ACK=1;
-
PSH:推送,接收方应立刻把数据交给应用层,不要缓存;
-
FIN:请求关闭连接,四次挥手使用;
-
RST:重置连接,异常断开连接;
-
URG:紧急标志,代表存在紧急数据。
五、TCP可靠性核心机制
1. 应答确认机制
每发送一段数据,接收方返回ACK确认号,告诉发送方:我已经收到到几号字节,下一次我期望收到几号。支持累计确认,可以一次确认多段数据。
2. 超时重传机制
发送数据同时开启计时器;如果超时还没有收到ACK应答,就自动重传该段报文,保证数据不会丢失。超时时间会动态调整。
3. 滑动窗口(流量控制)
流量控制:防止发送方发送太快,把接收方缓冲区打满。
接收方在TCP头部窗口字段告诉发送方自己还能接收多少字节;发送方严格遵守这个窗口大小发送数据。窗口不断"滑动",实现流水线传输,不用发一段等一段ACK,极大提高传输效率。
发送窗口实际大小 = min(接收方通告窗口,拥塞窗口)
4. 捎带应答机制
ACK确认报文不需要单独发;如果本端刚好有业务数据要发给对方,就把ACK确认"搭载"在业务数据包头部一起发送,减少报文数量。
5. 拥塞控制
防止发送方发送太快,把中间网络链路压垮。包含:慢启动、拥塞避免、快速重传、快速恢复算法。
六、TCP Socket全套编程API
TCP客户端、服务端完整流程
TCP服务端流程
socket() → bind()绑定IP端口 → listen()开启监听 → accept()阻塞等待客户端连接 → recv()/send()收发数据 → close()关闭套接字
TCP客户端流程
socket() → connect()发起连接(触发三次握手) → send()/recv()收发数据 → close()关闭套接字(触发四次挥手)
重点区分:listen返回监听套接字;accept返回通信套接字,真正用来和客户端收发数据。监听套接字只负责接收新连接,不能收发业务数据。
1.socket 创建套接字
include <sys/socket.h
int socket(int domain, int type, int protocol);
-
domain:AF_INET IPv4
-
type:SOCK_STREAM 代表TCP流式套接字
-
protocol:0
返回:成功返回套接字fd,失败1。
2.bind 绑定IP与端口(服务端必须调用)
int bind(int sockfd, const struct sockaddr addr, socklen_t addrlen);
把套接字和本机IP地址、端口绑定;客户端一般不需要bind,操作系统自动分配临时端口。
INADDR_ANY:监听本机所有网卡IP。
3.listen() 开启监听
int listen(int sockfd, int backlog);
-
sockfd:socket返回监听套接字
-
backlog:未完成+已完成三次握手的连接队列最大数目。
返回值:成功0,失败1。
listen之后套接字从主动套接字变为被动监听套接字,等待客户端连接。
4.accept() 接收客户端连接
int accept(int sockfd, struct sockaddr addr, socklen_t addrlen);
功能:阻塞等待,等待完成三次握手的客户端连接到来。
-
sockfd:监听套接字
-
addr:输出参数,保存客户端IP端口信息,可以填NULL不关心客户端地址。
-
addrlen:地址长度,输入输出参数。
返回值:成功返回全新的通信套接字connfd;后续读写数据全部使用connfd;失败1。
注意:监听套接字继续存在,可以继续接收下一个客户端。
5.connect() 客户端发起连接
int connect(int sockfd, const struct sockaddr addr, socklen_t addrlen);
客户端调用,向服务端IP端口发起TCP连接,底层触发三次握手。
- addr:存放服务端IP端口信息。
返回值:成功0;失败1。
6.send()发送数据
ssize_t send(int sockfd, const void buf, size_t len, int flags);
- sockfd:通信套接字;flags一般写0。
返回:成功返回实际发送字节数;失败1。
send返回成功只是数据拷贝进入内核发送缓冲区,不等于数据已经到达对方主机。
7.recv()接收数据
ssize_t recv(int sockfd, void buf, size_t len, int flags);
- sockfd:通信套接字;flags=0。
返回值:
-
0:实际读到的字节;
-
返回0:对方已经正常关闭连接(对端执行close,四次挥手完成);
-
1:出错。
recv返回0是TCP非常重要判断条件,代表对方已经断开。
8.close()关闭套接字
int close(int fd);
关闭套接字文件描述符,会触发TCP四次挥手断开连接,释放资源。
七、UDP与TCP核心对比表
|-------------|------------------------|----------------------------------------|
| 对比项 | UDP | TCP |
| 连接 | 无连接 | 面向连接(三次握手建立,四次挥手释放) |
| 传输对象 | 面向数据报,保留报文边界 | 面向字节流,无报文边界 |
| 可靠性 | 不可靠,可能丢包乱序 | 可靠传输,确认、重传、流量拥塞控制 |
| 开销 | 小,头部 8 字节 | 大,头部最少 20 字节 |
| 实时性 | 高,适合直播游戏 | 较低,可靠性优先 |
| 典型 API | socket sendto recvfrom | socket connect listen accept send recv |
| 典型应用 | DNS、直播、音视频 | HTTP、HTTPS、FTP、MQTT |
八、补充:Wireshark抓包工具
Wireshark是网络抓包分析工具,可以抓取网卡数据包,观察SYN、ACK、FIN报文,分析三次握手四次挥手。
Linux安装命令:
bash
sudo aptget install wireshark
sudo wireshark
常用过滤条件示例:
tcp.port == 8080 抓取8080端口tcp包
udp.port == 5000
小结
-
TCP面向连接、可靠、字节流;UDP无连接不可靠面向数据报。
-
三次握手建立连接:SYN → SYN+ACK → ACK;同步序列号,确认双方收发能力。
-
四次挥手断开连接:FINACKFINACK;TIMEWAIT等待2MSL。
-
TCP头部6大标志位SYN/ACK/FIN/PSH/RST/URG要理解含义。
-
TCP可靠机制:确认应答、超时重传、滑动窗口流量控制、捎带应答、拥塞控制。
-
API重点:服务端socketbindlistenacceptrecv/sendclose;客户端socketconnectrecv/sendclose;accept返回通信套接字,listen套接字只管接收新连接;recv返回0代表对方正常关闭连接。