网络编程基础

一、网络发展和网络协议

1.1、网络发展

  • 独立模式:计算机之间相互独立
  • 网络互联:多台计算机链接在一起,完成数据共享
  • 局域网LAN:计算机数量更多,通过交换机和路由器连接在一起
  • 广域网WAN:将远隔千里的计算机都连接在一起
  • 所谓 "局域网" 和 "广域网" 只是一个相对的概念.

1.2、网络协议

1.2.1、OSI七层模型:

OSI七层模型称为开放式系统互联参考模型,是一个逻辑上的定义和规范。

分层名称 功能 功能概览
7 应用层 针对特定应用的协议 HTTP/HTTPS FTP(文件传输协议) SMTP(邮件传输协议) POP3(邮局协议)
6 表示层 设备固有数据格式和 网络标准数据格式的转换 加密 接收不同表现形式的信息 如文字流,图像,声音等 SSL/TLS
5 会话层 通信管理,负责简历和断开通信连接 管理传输层以下的分层 会话管理 何时建立连接 何时断开连接 以及保持多久的链接 RPC,NetBIOS
4 传输层 管理两个节点之间的数据传输 负责可靠传输 确保谁被可靠的传送到目的地 端到端传输 是否有数据丢失 TCP,UDP
3 网络层 地址管理和路由选择 路由 ,IP寻址 经过那个路由器传递到目标地址 IP,ICMP,Router
2 数据链路层 互联设备之间传送和识别数据帧 帧传输,MAC寻址 数据帧和比特流之间的转换 如:以太网。PPP。Switch
1 物理层 以"0","1"代表电压的高低, 灯光的闪灭 界定连接器和网线的规格 传输原始比特流 比特流和电子信号之间的切换, 连接器和网线的规格 如以太网,光纤,Hub
[OSI七层模型]

1.2.2、TCP/IP五层模型

TCP/IP是一组协议的代名词,它还包括许多协议,组成了TCP/IP协议簇.

TCP/IP通讯协议采用了5层的层级结构,每一层都呼叫它的下一层所提供的网络来完成自己的需求

**物理层:**负责光/电信号的传递方式. 比如现在以太网通用的网线(双绞 线)、早期以太网采用的的同轴电缆 (现在主要用于有线电视)、光纤, 现在的wifi无线网使用电磁波等都属于物理层的概念。物理层的能力决 定了最大传输速率、传输距离、抗干扰性等. 集线器(Hub)工作在物理层.

**数据链路层:**负责设备之间的数据帧的传送和识别. 例如网卡设备的驱动、帧同步(就是说从网线上检测 到什么信号算作新帧的开始)、冲突检测(如果检测到冲突就自动重发)、数据差错校验等工作. 有以太 网、令牌环网, 无线LAN等标准. 交换机(Switch)工作在数据链路层.

网络层: 负责地址管理和路由选择. 例如在IP协议中, 通过IP地址来标识一台主机, 并通过路由表的方式规 划出两台主机之间的数据传输的线路(路由). 路由器(Router)工作在网路层.

传输层: 负责两台主机之间的数据传输. 如传输控制协议 (TCP), 能够确保数据可靠的从源主机发送到目标 主机.

应用层: 负责应用程序间沟通,如简单电子邮件传输(SMTP)、文件传输协议(FTP)、网络远程访问 协议(Telnet)等. 我们的网络编程主要就是针对应用层.

1.3、数据包封装和分用

不同的协议层对数据包有不同的称谓,在传输层叫做段(segment),在网络层叫做数据报 (datagram),在链 路层叫做帧(frame). 应用层数据通过协议栈发到网络上时,每层协议都要加上一个数据首部(header),称为封装 (Encapsulation). 首部信息中包含了一些类似于首部有多长, 载荷(payload)有多长, 上层协议是什么等信息. 数据封装成帧后发到传输介质上,到达目的主机后每层协议再剥掉相应的首部, 根据首部中的 "上层协议 字段" 将数据交给对应的上层协议处理.

1.4、网络中的地址管理

1.4.1、IP地址

  • IP协议有两个版本, IPv4和IPv6. 凡是提到IP协议, 没有特殊说明的, 默认都是指IPv4
  • IP地址是在IP协议中, 用来标识网络中不同主机的地址;
  • 对于IPv4来说, IP地址是一个4字节, 32位的整数;
  • 我们通常也使用 "点分十进制" 的字符串表示IP地址, 例如 192.168.0.1 ; 用点分割的每一个数字表示一个 字节, 范围是 0 - 255;

1.4.2、MAC地址

  • MAC地址用来识别数据链路层中相连的节点;
  • 长度为48位, 及6个字节. 一般用16进制数字加上冒号的形式来表示(例如: 08:00:27:03:fb:19)
  • 在网卡出厂时就确定了, 不能修改. mac地址通常是唯一的(虚拟机中的mac地址不是真实的mac地址, 可 能会冲突; 也有些网卡支持用户配置mac地址)

二、理解源IP地址和目的IP地址

对于端口号的理解:

端口号(port)是传输层协议的内容。端口号是一个2字节16位的整数,用来标识一个进程,告诉操作系统,当前的这个数据要交给哪一个进程来处理。IP地址+端口号能够标识网络上的某一台主机的某一个进程。一个端口号只能被一个进程占用。

一个进程可以绑定多个端口号,但是一个端口号不能被多个进程绑定。

三、网络字节序

内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的多字节数据相对于文件中的偏 移地址也有大端小端之分, 网络数据流同样有大端小端之分。

  • 发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出;
  • 接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存;
  • 因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址. TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节.
  • 不管这台主机是大端机还是小端机, 都会按照这个TCP/IP规定的网络字节序来发送/接收数据;
  • 如果当前发送主机是小端, 就需要先将数据转成大端; 否则就忽略, 直接发送即可。

为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络 字节序和主机字节序的转换。

cpp 复制代码
#include<arpa/inet.h>

unit32_t htonl(unit32_t hostlong);
unit16_t htons(unit16_t hostshort);
unit32_t ntohl(unit32_t netlong);
unit16_t ntohs(unit16_t netshort);
  • 这些函数名很好记,h表示host,n表示network,l表示32位长整数,s表示16位短整数。 例如htonl表示将32位的长整数从主机字节序转换为网络字节序,例如将IP地址转换后准备发送。
  • 如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回;
  • 如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回。

四、socket

4.1、socket常见API

cpp 复制代码
// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);
//socket()打开一个网络通讯端口,如果成功的话,就像open()一样返回一个文件描述符;
//应用程序可以像读写文件一样用read/write在网络上收发数据;
//如果socket()调用出错则返回-1;
//对于IPv4, family参数指定为AF_INET; 
//对于TCP协议,type参数指定为SOCK_STREAM, 表示面向流的传输协议
//protocol参数的介绍从略,指定为0即可。 



// 绑定端口号 (TCP/UDP, 服务器) 
int bind(int socket, const struct sockaddr *address,socklen_t address_len);
//服务器程序所监听的网络地址和端口号通常是固定不变的,客户端程序得知服务器程序的地址和端口号后
//就可以向服务器发起连接; 服务器需要调用bind绑定一个固定的网络地址和端口号;
//bind()成功返回0,失败返回-1。 
//bind()的作用是将参数sockfd和myaddr绑定在一起, 使sockfd这个用于网络通讯的文件描述符监听
//myaddr所描述的地址和端口号; 
//前面讲过,struct sockaddr *是一个通用指针类型,myaddr参数实际上可以接受多种协议的sockaddr结构体,而它们的长度各不相同,所以需要第三个参数addrlen指定结构体的长度;


// 开始监听socket (TCP, 服务器)
int listen(int socket, int backlog);
//listen()声明sockfd处于监听状态, 并且最多允许有backlog个客户端处于连接等待状态, 如果接收到更多的连接请求就忽略, 这里设置不会太大(一般是5), 具体细节同学们课后深入研究;
//listen()成功返回0,失败返回-1;

// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr* address,socklen_t* address_len);
//三次握手完成后, 服务器调用accept()接受连接;
//如果服务器调用accept()时还没有客户端的连接请求,就阻塞等待直到有客户端连接上来;
//addr是一个传出参数,accept()返回时传出客户端的地址和端口号;
//如果给addr 参数传NULL,表示不关心客户端的地址;
//addrlen参数是一个传入传出参数(value-result argument), 传入的是调用者提供的, 缓冲区addr的长度以避免缓冲区溢出问题, 传出的是客户端地址结构体的实际长度(有可能没有占满调用者提供的缓冲区);


// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
//客户端需要调用connect()连接服务器;
//connect和bind的参数形式一致, 区别在于bind的参数是自己的地址, 而connect的参数是对方的地址; 
//connect()成功返回0,出错返回-1;

4.2、sockaddr结构

socket API是一层抽象的网络编程接口,适用于各种底层网络协议,如IPv4、IPv6,以及后面要讲的UNIX Domain Socket. 然而, 各种网络协议的地址格式并不相同。

  • IPv4和IPv6的地址格式定义在netinet/in.h中,IPv4地址用sockaddr_in结构体表示,包括16位地址类型, 16 位端口号和32位IP地址.
  • IPv4、IPv6地址类型分别定义为常数AF_INET、AF_INET6. 这样,只要取得某种sockaddr结构体的首地址, 不需要知道具体是哪种类型的sockaddr结构体,就可以根据地址类型字段确定结构体中的内容.
  • socket API可以都用struct sockaddr *类型表示, 在使用的时候需要强制转化sockaddr_in; 这样的好 处是程序的通用性, 可以接收IPv4, IPv6, 以及UNIX Domain Socket各种类型的sockaddr结构体指针做为 参数;

4.3、简单实现一个UDP和TCP网络程序、

代码链接:简易UDP

代码链接:简易TCP

五、HTTP协议

5.1、HTTP协议格式

一个HTTP请求由以下4部分组成:<请求行>、<请求头>、<空行>、<请求体>(可选)

5.1.1、请求行

  • 格式<方法> <请求URI> <HTTP版本>
    示例
    GET /index.html HTTP/1.1

  • 关键字段

    • 方法 :定义操作类型,如 GET(获取资源)、POST(提交数据)、PUT(更新资源)、DELETE(删除资源)等。

    • 请求URI :目标资源的路径(如 /api/data)或完整URL(代理场景)。

    • HTTP版本 :如 HTTP/1.1HTTP/2

5.2.1、请求头

  • 以键值对形式传递附加信息,每行一个头字段,格式为 Header-Name: value

  • 常见请求头

    • Host: www.example.com(目标主机,HTTP/1.1必需)

    • User-Agent: Mozilla/5.0(客户端标识)

    • Content-Type: application/json(请求体的数据类型)

    • Content-Length: 128(请求体的字节长度)

    • Authorization: Bearer token123(身份验证凭证)

5.1.3、 空行

  • 请求头结束后需一个空行(\r\n),表示头部结束。

5.1.4、 请求体(Request Body)

  • 适用场景POSTPUT等方法需要传递数据时使用。

  • 示例(JSON数据):

    复制代码
    {"username": "admin", "password": "123456"}
html 复制代码
完整HTTP请求示例

POST /login HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0
Content-Type: application/json
Content-Length: 42

{"username": "admin", "password": "123456"}

5.2、HTTP响应格式

<状态行><响应头><空行><响应体>(可选)

5.2.1. 状态行(Status Line)

  • 格式<HTTP版本> <状态码> <原因短语>
    示例HTTP/1.1 200 OK

  • 关键字段

    • 状态码:3位数字,表示请求结果。如:

      • 200 OK:成功

      • 404 Not Found:资源未找到

      • 500 Internal Server Error:服务器内部错误

    • 原因短语 :状态码的文本描述(如 OK)。

5.2.2. 响应头(Response Headers)

  • 格式与请求头类似,传递服务器信息或资源元数据。

  • 常见响应头

    • Content-Type: text/html(响应体类型)

    • Content-Length: 1024(响应体长度)

    • Set-Cookie: sessionid=abc123(设置Cookie)

    • Cache-Control: max-age=3600(缓存控制)

5.2.3. 空行

  • 响应头结束后需一个空行(\r\n)。

5.2.4. 响应体(Response Body)

  • 服务器返回的实际内容,如HTML页面、JSON数据等。
html 复制代码
完整请求示例

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 127

<html>
  <body>
    <h1>Welcome to Example.com</h1>
  </body>
</html>

5.3、请求格式和响应格式总结

组件 请求格式 响应格式
起始行 方法 URI 版本(如 GET / HTTP/1.1 版本 状态码 原因短语(如 HTTP/1.1 200 OK
头部 客户端信息(Host、User-Agent等) 服务器信息(Content-Type、Set-Cookie等)
空行 必须存在(\r\n 必须存在(\r\n
主体 可选(如POST数据) 可选(如HTML页面)

5.4、HTTP请求分的方法

方法类型 方法名称 核心用途
安全方法 GET、HEAD、OPTIONS 不修改服务器资源
非安全方法 POST、PUT、DELETE、PATCH 可能修改服务器资源
幂等方法 GET、PUT、DELETE、HEAD、OPTIONS、TRACE 多次请求效果相同
非幂等方法 POST、PATCH 多次请求可能产生不同结果
缓存支持方法 GET、HEAD 响应可被缓存
场景 推荐方法 原因
查询数据 GET 安全、幂等,支持缓存
创建新资源(ID由服务器生成) POST 非幂等,适合创建操作
全量更新资源(已知ID) PUT 幂等,需提供完整资源数据
删除资源 DELETE 幂等,明确资源标识
部分更新资源 PATCH 仅传递需修改的字段
跨域预检请求 OPTIONS 获取服务器支持的CORS方法

5.4.1、常见问题:post请求和get请求区别

特性 GET POST
语义 获取资源(查询) 提交数据(创建或触发操作)
数据位置 URL的查询字符串(Query String) 请求体(Body)
数据可见性 明文暴露在URL中(易被缓存、日志记录) 封装在请求体中(相对隐蔽)
安全性 安全方法(不修改服务器数据) 非安全方法(可能修改数据)
幂等性 幂等(多次请求结果相同) 非幂等(多次请求可能产生不同结果)
缓存 可被浏览器或代理缓存 默认不缓存(需显式指定缓存头)
数据长度限制 受URL长度限制(浏览器通常限制为2KB~8KB) 无严格限制(由服务器配置决定)
适用场景 搜索、分页、资源详情查询 登录、注册、文件上传、表单提交
浏览器行为 可收藏、可分享链接 无法直接通过URL重现操作
GET POST
核心目的 获取数据(安全、幂等) 提交数据(非安全、非幂等)
数据安全 低(URL暴露) 较高(Body传输)
适用操作 查询、搜索、分页 创建、更新、删除、触发业务逻辑
设计原则 遵循RESTful的"读"操作 遵循RESTful的"写"操作

5.5、HTTP状态码

状态码 类别 常见用途
200 成功 标准成功响应
301/302 重定向 资源路径变更
400 客户端错误 请求参数错误
401/403 客户端错误 认证/权限问题
404 客户端错误 资源不存在
500 服务器错误 服务器内部异常
503 服务器错误 服务过载或维护

核心原则

  • 2xx → 成功处理,可继续后续逻辑。

  • 3xx → 需遵循响应头重定向。

  • 4xx → 客户端需修改请求。

  • 5xx → 服务端问题,需排查修复。

5.6、HTTP端口号

端口号范围:0~65535(16位无符号整数),按用途分为三类:

端口类型 范围 典型用途 示例端口
知名端口 0~1023 系统核心服务 22 (SSH), 80 (HTTP)
注册端口 1024~49151 用户/企业应用 3306 (MySQL), 8080
动态端口 49152~65535 客户端临时通信 操作系统随机分配
5.6.1. 知名端口(0~1023)

特点

  • 绑定系统级服务(如HTTP、FTP等),普通用户程序默认无法使用。

  • 需要管理员权限(如Linux的root)才能监听这些端口。

常见端口示例

端口 协议/服务 用途
20/21 FTP 文件传输(数据/控制连接)
22 SSH 安全远程登录
25 SMTP 邮件发送
53 DNS 域名解析(UDP/TCP)
80 HTTP 网页访问
443 HTTPS 加密网页访问
3306 MySQL 数据库服务(虽属注册端口,但广泛使用)

5.6.2. 注册端口(1024~49151)

特点

  • 用于用户级应用程序或企业服务,需向IANA注册(非强制)。

  • 普通用户程序可绑定,但建议避免冲突(如避免使用已约定俗成的端口)。

常见端口示例

端口 协议/服务 用途
1433 MSSQL Microsoft SQL Server
1521 Oracle DB Oracle数据库默认端口
2049 NFS 网络文件系统
3306 MySQL 数据库服务
3389 RDP 远程桌面协议
5432 PostgreSQL PostgreSQL数据库
6379 Redis 内存数据库服务
8080 HTTP-Alt 替代HTTP端口(如Tomcat默认)

5.6.3. 动态/私有端口(49152~65535)

特点

  • 客户端发起连接时由操作系统临时分配,通信结束后释放。

  • 无固定用途,避免与服务端端口冲突。

示例场景

浏览器访问网页时,本地生成动态端口(如52000)与服务器的80端口通信。、

5.6.4.常见问题

为什么1024以下端口需要特权权限?

:防止普通用户程序占用系统关键服务端口,确保系统稳定性。

Q2: 如何查看当前系统的端口占用?

Linux/Unix

复制代码
netstat -tuln    # 查看监听中的TCP/UDP端口
ss -tunlp        # 更高效的替代命令
lsof -i :80      # 查看占用80端口的进程

Q3: 端口号能否重复使用?

:同一协议(TCP/UDP)的同一端口在同一时刻只能被一个进程绑定,但可通过SO_REUSEADDR选项复用(需谨慎)。

6.TCP和UDP

6.1、UDP

6.1.1、UDP协议概述

定位:传输层协议(基于IP协议)。

核心特性

  • 无连接:无需预先建立连接,直接发送数据。每个数据报独立处理,无握手或状态维护。

  • 不可靠传输:不保证数据到达、不重传、不维护顺序。无确认、重传或排序机制,依赖上层协议处理丢包和乱序。

  • 轻量高效:头部开销小(仅8字节),适合低延迟场景。

6.1.2、UDP数据格式

html 复制代码
 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 
+---------------+---------------+---------------+---------------+
|     Source Port (16 bits)     |  Destination Port (16 bits)   |
+---------------+---------------+---------------+---------------+
|      Length (16 bits)         |     Checksum (16 bits)        |
+---------------+---------------+---------------+---------------+
|                          Payload (变长)                        |
+---------------------------------------------------------------+
字段详解
字段 长度 含义
Source Port 16 bits 源端口号:发送方的应用程序端口号(可选,若为0表示不指定)。
Destination Port 16 bits 目标端口号:接收方的应用程序端口号(必需)。
Length 16 bits UDP数据报总长度:包括头部和数据部分,最小值为8(仅有头部)。
Checksum 16 bits 校验和:检测头部和数据的传输错误(可选,IPv4中可为0,IPv6中必须计算)。
Payload 变长 数据内容:上层协议(如DNS、RTP)传递的实际数据。

6.1.3、UDP适用场景

场景 原因
实时音视频传输 低延迟优先,容忍少量丢包(如Zoom、VoIP)。
DNS查询 请求-响应模式,快速且数据量小,重试成本低。
广播/组播 UDP支持一对多通信(如IPTV、在线游戏状态同步)。
IoT设备通信 资源受限设备适合轻量协议(如传感器数据上报)。

6.2、TCP

6.2.1、TCP协议概述

定位 :传输层协议,提供可靠面向连接的字节流服务。

核心特性

  • 可靠性:通过确认应答、超时重传、流量控制等机制确保数据完整有序。

  • 面向连接 :需通过三次握手 建立连接,四次挥手终止连接。

  • 全双工通信:双方可同时发送和接收数据。

  • 拥塞控制:动态调整发送速率以适应网络状况。

6.2.2、TCP报文格式

TCP报文由**头部(Header)数据部分(Payload)**组成,头部最小20字节(最大60字节,含选项):

html 复制代码
 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 
+---------------+---------------+---------------+---------------+
|          Source Port (16 bits)        |    Destination Port (16 bits)     |
+---------------+---------------+---------------+---------------+
|                        Sequence Number (32 bits)                        |
+---------------+---------------+---------------+---------------+
|                     Acknowledgment Number (32 bits)                     |
+---------------+---------------+---------------+---------------+
| Data Offset | Reserved |Control Flags|         Window Size (16 bits)      |
+---------------+---------------+---------------+---------------+
|         Checksum (16 bits)            |         Urgent Pointer (16 bits)  |
+---------------+---------------+---------------+---------------+
|                       Options (0~40 bytes, optional)                    |
+---------------+---------------+---------------+---------------+
|                               Payload (变长)                             |
+-----------------------------------------------------------------------+
字段详解
字段 长度 作用
Source/Dest Port 16 bits 源/目标端口号(标识应用程序)。
Sequence Number 32 bits 序列号:当前报文段第一个字节的编号(保证数据有序)。
Acknowledgment Num 32 bits 确认号:期望收到的下一字节的序列号(用于ACK应答)。
Data Offset 4 bits 头部长度(以4字节为单位,最小值为5,即20字节)。
Control Flags 9 bits 控制标志位(如SYN、ACK、FIN等,见下表)。
Window Size 16 bits 接收窗口大小:告知发送方可发送的数据量(流量控制)。
Checksum 16 bits 校验和:覆盖头部、数据和伪头部(类似UDP)。
Urgent Pointer 16 bits 紧急指针:标识紧急数据的末尾位置(需设置URG标志)。
控制标志位
标志位 名称 含义
SYN 同步 建立连接时同步序列号(三次握手使用)。
ACK 确认 确认号有效(多数报文ACK=1)。
FIN 结束 请求终止连接(四次挥手使用)。
RST 复位 强制断开连接(异常处理)。
PSH 推送 接收方应尽快将数据交给应用层。
URG 紧急 紧急数据需优先处理(配合紧急指针)。

6.2.3、TCP状态机

状态 描述
CLOSED 初始状态,表示无连接。
LISTEN 服务器等待连接请求(SYN)。
SYN_SENT 客户端已发送SYN,等待ACK。
SYN_RCVD 服务器收到SYN并发送SYN-ACK,等待ACK。
ESTABLISHED 连接已建立,可正常传输数据。
FIN_WAIT_1 主动关闭方发送FIN,等待ACK。
FIN_WAIT_2 收到对端ACK,等待对端FIN。
CLOSE_WAIT 被动关闭方收到FIN并发送ACK,等待应用层关闭。
LAST_ACK 被动关闭方发送FIN,等待ACK。
TIME_WAIT 主动关闭方收到FIN并发送ACK,等待2MSL(确保报文消失)。

6.2.4、三次握手和四次挥手

三次握手(建立连接)
html 复制代码
   Client                              Server
     |                                    |
     |          SYN (seq=x)              →| 客户端发送SYN,进入SYN_SENT状态
     |←         SYN-ACK (seq=y, ack=x+1)  | 服务器响应SYN-ACK,进入SYN_RCVD状态
     |          ACK (ack=y+1)            →| 客户端确认,双方进入ESTABLISHED状态
  • 目的:同步初始序列号(ISN),协商窗口大小和MSS(最大报文段长度)。
四次挥手(终止连接)
html 复制代码
   Client                              Server
     |                                    |
     |          FIN (seq=u)              →| 客户端发起关闭,进入FIN_WAIT_1
     |←         ACK (ack=u+1)            | 服务器确认,进入CLOSE_WAIT
     |←         FIN (seq=v, ack=u+1)     | 服务器发起关闭,进入LAST_ACK
     |          ACK (ack=v+1)            →| 客户端确认,进入TIME_WAIT(等待2MSL)
  • TIME_WAIT作用:确保最后一个ACK到达,防止旧连接报文干扰新连接。

6.2.5、TCP应用场景

场景 原因
文件传输 需确保数据完整(如FTP、HTTP文件下载)。
网页浏览 HTTP/HTTPS依赖TCP可靠传输HTML、CSS、JS等资源。
电子邮件 SMTP、POP3、IMAP协议需要可靠传递邮件内容。
数据库操作 SQL查询结果需准确无误(如MySQL、PostgreSQL)。

6.3、TCP和UDP的区别

TCP:

面向连接, 传输数据需要通过三次握手建立连接,通过四次挥手断开连接。

可靠传输 ,通过应答(ACK),超时重传,流量控制和拥塞控制确保数据完整,有序到达

字节流模式 ,数据无边界,可能合并和拆分,(需要应用层处理粘包、拆包问题)

效率低 ,头部较大(10字节+选项),且需要额外控制机制,如连接管理,重传

动态调整速率 ,通过滑动窗口,拥塞算法适应网络状况,避免拥塞。

一对一通信,每条连接仅支持两个端点。

UDP

无连接。 直接发送数据,无需预先建立连接。
不可靠传输 。不保证数据到达或顺序,可能丢包、乱序。
数据报模式 。每个数据包独立且有明确边界,接收端按发送次数读取。

效率高 。头部仅8字节,无额外控制开销,适合实时性要求高的场景。

无控制机制。 可能持续高速发送数据,易导致网络拥塞。

**支持一对一、一对多、多对多。**适用于广播、组播(如IP电话)。

特性 TCP UDP
连接性 面向连接 无连接
可靠性 高(确保数据完整) 低(可能丢包)
传输效率 较低(控制开销大) 高(开销小)
数据边界 字节流(需处理粘包) 数据报(保留边界)
适用场景 文件传输(FTP)、网页(HTTP/HTTPS)、邮件(SMTP) 实时通信、广播、视频会议

6.4、TCP常见问题

6.4.1、粘包问题

由于TCP是字节流协议,数据无明确边界,导致:

  • 粘包:多个数据包被合并接收(发送方快速写入小包,接收方缓冲区未及时读取)。

  • 拆包:单个数据包被拆分接收(数据包大于接收缓冲区大小或MSS)。

解决方案对比表

方法 实现方式 优点 缺点 适用场景
固定长度法 每个数据包固定长度,不足部分填充空字符。 实现简单,解析高效 浪费带宽,灵活性差 心跳检测、固定指令(如传感器上报)
分隔符法 在数据包末尾添加特殊分隔符(如\n\r\n或自定义字符)。 直观易调试,适合文本协议 需处理分隔符转义,大数据效率低 HTTP头、Redis协议、日志传输
长度前缀法 在数据头部添加长度字段(如4字节整数),标明后续数据的实际长度。 灵活高效,通用性强 需解析头部,增加复杂度 二进制协议(gRPC、自定义协议)
高级协议法 使用标准协议(如HTTP/2的帧结构)或自定义协议(TLV格式:类型+长度+值)。 扩展性强,支持复杂业务逻辑 学习成本高,实现复杂 高并发场景(金融交易、流媒体)

避免粘包策略表

策略 具体操作 注意事项
明确数据边界 设计应用层协议时强制定义数据边界(如长度前缀或分隔符)。 避免混合使用多种边界标识,确保协议一致性。
使用成熟协议 优先采用现成协议(如HTTP/2、MQTT),其内部已处理粘包问题。 避免重复造轮子,减少开发成本。
合理设计包大小 控制单个数据包不超过MTU(通常1500字节),减少拆包概率。 需结合业务场景平衡数据完整性与传输效率。
缓冲区管理 接收方维护缓冲区,按规则拼接和拆分数据包。 处理半包时需等待后续数据,避免逻辑错误。
超时与异常处理 设置读取超时,丢弃不完整数据包并重置连接。 防止恶意攻击或网络异常导致资源耗尽。
测试与验证 模拟网络延迟、拆包场景,验证协议健壮性。 使用工具(如Wireshark)抓包分析。
相关推荐
白帽少女安琪拉8 分钟前
24.pocsuite3:开源的远程漏洞测试框架
网络·网络安全
熬夜苦读学习1 小时前
进程间通信--匿名管道
运维·服务器
Dream Algorithm1 小时前
DICT领域有哪些重要的技术标准和规范?
网络·物联网·边缘计算
霸气的哦尼酱1 小时前
同一子网通信
网络·智能路由器
对你无可奈何1 小时前
高可用环境下Nginx服务管理脚本优化实践
linux·运维·nginx
go_to_hacker2 小时前
奇安信二面
网络·web安全·网络安全·渗透测试·代码审计·春招
前端白袍2 小时前
性能优化:服务器性能影响网站加载速度分析
运维·服务器·性能优化
stone08232 小时前
ABAP语言的动态编程(4) - 综合案例:管理费用明细表
linux·运维·服务器
一袋米扛几楼982 小时前
【Node】Node.js环境变量配置,及下载地址
javascript·网络·node.js
He_Donglin3 小时前
从人工智能窥见网络安全的重要性
网络·人工智能·web安全