Linux应用软件编程|TCP协议与Socket全套编程(三次握手、四次挥手、报文头部、核心机制)

一、TCP协议基础特点

TCP(Transmission Control Protocol)传输控制协议

  1. 面向连接:通信之前必须建立连接,通信结束要断开连接;

  2. 面向字节流:把数据当成一串字节流,没有报文边界;

  3. 可靠传输:通过三次握手、应答确认、超时重传、滑动窗口等机制,保证数据无丢失、无重复、按序到达;

  4. 协议机制复杂,相比UDP开销更大,实时性弱于UDP。

适用场景:网页、文件传输、MQTT;不适合直播、游戏这类追求低延迟可容忍少量丢包场景。

二、TCP三次握手(建立连接)

客户端主动发起连接,三次握手目的:同步双方初始序列号,确认双方收发能力正常。

  1. 第一次握手:客户端发送SYN报文,携带客户端初始序列号seq=x,客户端进入SYN_SENT状态。

SYN标志位=1,表示请求建立连接。

  1. 第二次握手:服务端收到SYN,回复SYN+ACK报文;ACK确认号ack=x+1,同时携带服务端自己的初始序列号seq=y;服务端进入SYN_RCVD状态。

  2. 第三次握手:客户端收到SYN+ACK,回复ACK确认报文,确认号ack=y+1。客户端、服务端都进入ESTABLISHED(连接建立完成状态),之后就可以收发业务数据。

思考:为什么不能两次握手?

防止网络中滞留的旧无效连接报文到达服务器,服务器单方面建立无效连接,浪费服务器资源。

三、TCP四次挥手(断开连接)

TCP连接是全双工,两边可以独立关闭自己发送方向,因此断开需要四次。主动关闭方一般是客户端。

  1. 第一次挥手:客户端发送FIN报文,表示客户端不再发送数据,进入FIN_WAIT_1。

FIN标志位=1,代表请求关闭连接。

  1. 第二次挥手:服务端回复ACK确认FIN报文,客户端收到ACK进入FIN_WAIT_2。此时客户端不再发数据,但是服务端仍然可以继续向客户端发送剩余数据。

  2. 第三次挥手:当服务端业务数据全部发送完毕,服务端发送FIN报文,服务端进入LAST_ACK。

  3. 第四次挥手:客户端回复ACK确认FIN报文;客户端进入TIME_WAIT(等待2MSL);服务端收到ACK直接进入CLOSED;客户端等待2MSL时间过后,也进入CLOSED,连接彻底释放。

TIMEWAIT作用:

  1. 保证对方可以收到自己最后的ACK报文;

  2. 等待网络中该连接残留的旧数据包全部过期消失,避免干扰下一次新连接。

四、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。

返回值:

  1. 0:实际读到的字节;

  2. 返回0:对方已经正常关闭连接(对端执行close,四次挥手完成);

  3. 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

小结

  1. TCP面向连接、可靠、字节流;UDP无连接不可靠面向数据报。

  2. 三次握手建立连接:SYN → SYN+ACK → ACK;同步序列号,确认双方收发能力。

  3. 四次挥手断开连接:FINACKFINACK;TIMEWAIT等待2MSL。

  4. TCP头部6大标志位SYN/ACK/FIN/PSH/RST/URG要理解含义。

  5. TCP可靠机制:确认应答、超时重传、滑动窗口流量控制、捎带应答、拥塞控制。

  6. API重点:服务端socketbindlistenacceptrecv/sendclose;客户端socketconnectrecv/sendclose;accept返回通信套接字,listen套接字只管接收新连接;recv返回0代表对方正常关闭连接。

相关推荐
2301_780789663 小时前
CDN提供商常用的DDoS缓解技术与策略
linux·运维·服务器·人工智能·架构
夏炳辉.3 小时前
Rocky Linux 8 从零安装 psql(PostgreSQL 客户端)
linux·运维·postgresql
β添砖java3 小时前
学习笔记:实战章节:在Linux上部署各类软件
linux·笔记·学习
隔窗听雨眠3 小时前
大模型实时通信协议深度对比:SSE、WebSocket与gRPC的选型指南与实战解析
网络·websocket·网络协议
老当益壮梁奶奶3 小时前
Linux软件编程学习笔记(十一):深入浅出 TCP 协议与 Socket 编程实践
linux·c语言·笔记·学习·tcp/ip
speop4 小时前
hell-gpu| TASK01-2
linux·运维·算法
byte轻骑兵4 小时前
【BlueZ 】用户态入口:main.c 核心函数与程序启动流程
linux·人工智能·bluez·电脑蓝牙·嵌入式蓝牙
唐古乌梁海4 小时前
传输协议https-TCP
网络协议·tcp/ip·https
Tisfy5 小时前
LeetCode 2058.找出临界点之间的最小和最大距离:遍历+遇到极值则更新(这种题谁空间复杂度不是O(1)啊)
linux·数据库·leetcode·链表·题解·模拟·遍历