通信协议与网络知识:从硬件到互联网的全面指南
通信协议是现代计算系统的基石,从嵌入式设备的硬件通信到互联网的数据传输,协议无处不在。本文将全面介绍从硬件层到网络层的核心通信协议,包括SPI、I2C、UART、TCP/IP和HTTP等,帮助你构建完整的通信协议知识体系,从入门到精通。一、硬件层通信协议详解
1.1 SPI协议(Serial Peripheral Interface)
基本特性:
全双工同步串行通信
主从架构:1个主设备控制多个从设备
高速传输:可达10Mbps甚至更高
四线制:
SCLK:时钟信号(主设备产生)
MOSI:主出从入(Master Out Slave In)
MISO:主入从出(Master In Slave Out)
SS/CS:片选信号(Slave Select/Chip Select)
工作模式:
通过时钟极性(CPOL)和时钟相位(CPHA)定义四种模式:
模式0:CPOL=0,CPHA=0(时钟空闲低电平,第一个边沿采样)
模式1:CPOL=0,CPHA=1(时钟空闲低电平,第二个边沿采样)
模式2:CPOL=1,CPHA=0(时钟空闲高电平,第一个边沿采样)
模式3:CPOL=1,CPHA=1(时钟空闲高电平,第二个边沿采样)
典型应用:
存储器(Flash、EEPROM)
传感器(加速度计、陀螺仪)
显示屏(OLED、TFT)
配置示例(STM32 HAL库):
SPI_HandleTypeDef hspi;
void SPI_Init(void) {
hspi.Instance = SPI1;
hspi.Init.Mode = SPI_MODE_MASTER;
hspi.Init.Direction = SPI_DIRECTION_2LINES;
hspi.Init.DataSize = SPI_DATASIZE_8BIT;
hspi.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi.Init.NSS = SPI_NSS_SOFT;
hspi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
hspi.Init.FirstBit = SPI_FIRSTBIT_MSB;
HAL_SPI_Init(&hspi);
}
uint8_t SPI_Transfer(uint8_t data) {
uint8_t received;
HAL_SPI_TransmitReceive(&hspi, &data, &received, 1, HAL_MAX_DELAY);
return received;
}
c
运行
1.2 I2C协议(Inter-Integrated Circuit)
基本特性:
半双工同步串行通信
两线制:
SDA:串行数据线
SCL:串行时钟线
多主多从:支持总线仲裁
中速传输:标准模式100kbps,快速模式400kbps,高速模式3.4Mbps
7位/10位地址:理论上可连接112/1008个设备
通信流程:
起始条件:SCL高电平时SDA从高到低
地址传输:7位地址+1位读写方向(0写,1读)
应答信号:每字节后接收方发送ACK(低)或NACK(高)
数据传输:每次传输8位数据
停止条件:SCL高电平时SDA从低到高
典型应用:
温度传感器(LM75)
实时时钟(DS1307)
EEPROM存储器(24C02)
配置示例(Arduino Wire库):
#include <Wire.h>
void setup() {
Wire.begin(); // 作为主设备
Serial.begin(9600);
}
void loop() {
// 写入数据到地址为0x68的设备
Wire.beginTransmission(0x68);
Wire.write(0x00); // 寄存器地址
Wire.write(0x55); // 数据
Wire.endTransmission();
// 从地址为0x68的设备读取数据
Wire.beginTransmission(0x68);
Wire.write(0x00); // 寄存器地址
Wire.endTransmission(false); // 不发送停止条件
Wire.requestFrom(0x68, 1); // 请求1字节数据
if (Wire.available()) {
byte data = Wire.read();
Serial.println(data, HEX);
}
delay(1000);
}
cpp
1.3 UART协议(Universal Asynchronous Receiver/Transmitter)
基本特性:
异步串行通信(无时钟线)
全双工:独立发送(TX)和接收(RX)线路
可配置参数:
波特率(常见9600, 115200等)
数据位(5-9位,通常8位)
停止位(1, 1.5, 2位)
校验位(无、奇、偶校验)
起始位和停止位:
起始位:1位低电平
停止位:1位或更多高电平
通信格式:
[空闲] [起始位0] [数据位D0-D7] [校验位] [停止位1] [空闲]
典型应用:
调试信息输出
GPS模块
蓝牙模块
配置示例(Linux串口编程):
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
int open_serial_port(const char *device, int baud) {
int fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1) return -1;
struct termios options;
tcgetattr(fd, &options);
// 设置波特率
cfsetispeed(&options, baud);
cfsetospeed(&options, baud);
// 8N1配置
options.c_cflag &= ~PARENB; // 无校验
options.c_cflag &= ~CSTOPB; // 1位停止位
options.c_cflag &= ~CSIZE;// 清除数据位掩码
options.c_cflag |= CS8; // 8位数据位
// 启用接收和本地模式
options.c_cflag |= (CLOCAL | CREAD);
// 禁用流控
options.c_cflag &= ~CRTSCTS;
// 原始输入模式
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
// 原始输出模式
options.c_oflag &= ~OPOST;
tcsetattr(fd, TCSANOW, &options);
return fd;
}
c
运行
1.4 硬件协议对比
二、网络层协议详解
2.1 TCP/IP协议栈
四层模型:
应用层:HTTP、FTP、SMTP等
传输层:TCP、UDP
网络层:IP、ICMP
网络接口层:以太网、Wi-Fi等
数据封装:
[应用数据]
[应用数据]
[应用数据]
[帧头部][应用数据][帧尾部]
2.2 TCP协议(Transmission Control Protocol)
核心特性:
面向连接:需先建立连接
可靠传输:确认、重传机制
流量控制:滑动窗口机制
拥塞控制:慢启动、拥塞避免等算法
全双工:双向数据流
三次握手:
客户端发送SYN=1, seq=x
服务端回复SYN=1, ACK=1, seq=y, ack=x+1
客户端发送ACK=1, seq=x+1, ack=y+1
四次挥手:
主动方发送FIN=1, seq=u
被动方回复ACK=1, ack=u+1
被动方发送FIN=1, seq=v
主动方回复ACK=1, ack=v+1
TCP头部结构:
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 | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Data | |U|A|P|R|S|F| |
| Offset| Reserved|R|C|S|S|Y|I| Window |
| | |G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2.3 UDP协议(User Datagram Protocol)
核心特性:
无连接:无需建立连接
不可靠:不保证交付、不保证顺序
简单高效:头部仅8字节
适合场景:实时应用、广播/多播
UDP头部结构:
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 | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Length | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2.4 HTTP协议(HyperText Transfer Protocol)
HTTP/1.1特性:
持久连接
管道化请求
分块传输编码
缓存控制
HTTP请求方法:
GET:获取资源
POST:提交数据
PUT:替换资源
DELETE:删除资源
HEAD:获取头部信息
HTTP状态码:
1xx:信息响应
2xx:成功(200 OK)
3xx:重定向(301 Moved Permanently)
4xx:客户端错误(404 Not Found)
5xx:服务器错误(500 Internal Server Error)
三、面试重点与实战应用
3.1 高频面试题解析
问题1:TCP三次握手为什么不是两次?
答案:防止历史重复连接初始化造成的资源浪费。如果只有两次握手,网络延迟导致的重传SYN可能会被误认为是新的连接请求。
问题2:TCP粘包问题如何解决?
解决方案:
固定长度消息
特殊分隔符(如\n)
长度前缀法(先发送消息长度)
应用层协议设计(如HTTP的Content-Length)
问题3:SPI主从模式如何实现多从设备通信?
答案:通过独立的片选信号(SS)控制。主设备通过拉低对应从设备的SS线来选择通信对象,同一时间只能与一个从设备通信。
3.2 实战案例分析
案例1:嵌入式传感器数据采集系统
硬件配置:
MCU:STM32F103
温度传感器:I2C接口(LM75)
加速度计:SPI接口(MPU6050)
调试输出:UART转USB
软件设计:
void read_sensors(void) {
// 读取I2C温度传感器
float temp = read_i2c_temp();
// 读取SPI加速度计
float accel;
select_spi_slave(ACCEL_SS);
read_spi_accel(accel);
deselect_spi_slave(ACCEL_SS);
// 通过UART输出
printf("Temp: %.2f, Accel: %.2f,%.2f,%.2f\n",
temp, accel, accel, accel);
}
c
运行
案例2:基于TCP的简单文件传输程序
服务端代码(Python示例):
import socket
def start_server():
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('0.0.0.0', 12345))
server.listen(1)
conn, addr = server.accept()
with open('received_file', 'wb') as f:
while True:
data = conn.recv(1024)
if not data:
break
f.write(data)
conn.close()
python
运行
客户端代码:
def send_file(filename):
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('server_ip', 12345))
with open(filename, 'rb') as f:
client.sendfile(f)
client.close()
python
运行
3.3 性能优化技巧
TCP优化:
调整缓冲区大小:
int sock_buf_size = 1024 * 1024; // 1MB
setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &sock_buf_size, sizeof(sock_buf_size));
setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sock_buf_size, sizeof(sock_buf_size));
c
运行
禁用Nagle算法(适合实时应用):
int flag = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag));
c
运行
启用TCP快速打开(TFO):
# Linux系统设置
echo 3 > /proc/sys/net/ipv4/tcp_fastopen
bash
SPI优化:
使用DMA传输减少CPU占用
合理设置时钟分频(平衡速度与稳定性)
硬件片选优于软件模拟
四、学习路径与资源推荐
4.1 分阶段学习计划
初级阶段(1-2周):
掌握UART通信,实现MCU与PC通信
学习I2C协议,连接温度传感器
理解TCP三次握手/四次挥手
中级阶段(3-4周):
实现SPI驱动OLED显示
开发简单的TCP Echo服务器
分析HTTP请求/响应结构
高级阶段(4周+):
研究TCP拥塞控制算法
实现多从设备SPI通信系统
开发基于HTTP的RESTful API
4.2 推荐资源
书籍:
《TCP/IP详解 卷1:协议》
《嵌入式系统开发之道——通信协议篇》
《HTTP权威指南》
在线工具:
Wireshark网络协议分析器
Postman HTTP API测试工具
SPI/I2C逻辑分析仪(Saleae)
开发板:
STM32 Discovery Kit(SPI/I2C/UART)
Raspberry Pi(网络编程)
ESP32(Wi-Fi/BLE)
通过系统学习这些通信协议,你将能够自如地在硬件和网络层面设计和优化通信系统,解决实际工程中的各种通信问题。记住,理解协议背后的设计思想比单纯**规则更重要,这将帮助你在面对新协议时能够快速掌握其核心原理。
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/niuTyler/article/details/146922205
页:
[1]