网络基础与 UDP 套接字编程
·
一、网络模型
1. OSI 七层模型
- 应用层:要传输的业务内容,给应用程序使用
- 表示层:对数据做加密、解密、格式转换
- 会话层:建立、管理会话链接
- 传输层:负责端到端数据传输,代表协议 TCP、UDP
- 网络层:路由选择,跨主机寻址,IP 协议
- 数据链路层:局域网内部数据传输,MAC 帧
- 物理层:网线、网卡等硬件介质
2. TCP/IP 四层模型(实际 Linux 内核使用)
- 应用层:HTTP、FTP、DNS、TFTP、TELNET、SMTP
- 传输层:TCP、UDP
- 网络层:IP、ARP/RARP
- 网络接口层:网卡驱动、硬件接口
OSI 是理论标准;TCP/IP 是现实工业实现。
二、传输层两大协议
UDP 用户数据报协议
- ✅ 无连接,不需要建立连接
- ✅ 资源开销小,速度快
- ❌ 不可靠,不确认、不重传,会丢包乱序
- ✅ 面向数据报,数据包边界保留,不会粘包
适用:DNS、直播、视频通话、游戏
TCP 传输控制协议
- ✅ 有连接:三次握手建立连接
- ✅ 可靠传输:确认应答、丢包重传
- ✅ 四次挥手断开连接
- ✅ 拥塞控制、滑动窗口
- ❌ 占用资源大,速度慢
- ❌ 字节流,会发生粘包
适用:文件下载、网页浏览,对数据完整性要求高场景。
三、网络层 IP 协议
1. IPv4 地址格式:网络位 + 主机位
- 网络位:标识是哪一个局域网
- 主机位:局域网内部是哪一台设备
例:192.168.0.175
广播地址:网络位不变,主机位全部置 1,向局域网所有主机发消息。例:192.168.0.255
子网掩码:区分网络位和主机位;二进制 1 代表网络位,0 代表主机位。192.168.0.175 /24,代表前 24 位是网络位。
2. IP 地址分类表格
| 分类 | 地址范围 | 用途 |
|---|---|---|
| A 类 | 1.0.0.0‑126.255.255.255 | 大型网络 |
| B 类 | 128.0.0.0‑191.255.255.255 | 中型网络 |
| C 类 | 192.0.0.0‑223.255.255.255 | 小型局域网,最常用 |
| D 类 | 224.0.0.0‑239.255.255.255 | 组播、广播 |
| E 类 | 240.0.0.0‑255.255.255.255 | 实验保留 |
私有 IP(内网,不能直接上互联网)
- A 类:
10.x.x.x - B 类:
172.16‑172.31.x.x - C 类:
192.168.x.x
公网 IP:可以直接访问互联网。
配套协议
- ARP:IP 地址 → MAC 物理地址
- RARP:MAC → IP 地址
四、网络字节序(重点)
网络传输统一使用大端序:高字节放在低地址。主机有可能大端、小端;网络一定大端。
主机字节序(小端) → 网络字节序(大端),必须转换!
1. htons
uint16_t htons(uint16_t hostshort);
- 参数:hostshort:主机字节序的 16 位短整型(端口号)
- 返回值:网络大端序的 16 位数
- 作用:
hhost 主机,to转换,nnet 网络,sshort 16 位 - 注意点:端口号一定要用 htons 转换,不转换会通信异常
- 比喻:把本地语言翻译成网络通用语言
2. inet_addr
in_addr_t inet_addr(const char *cp);
- 参数:cp 字符串 IP,例如
"192.168.1.100" - 返回值:网络字节序的 32 位整数 IP
- 作用:把点分十进制字符串 IP,转成网络大端整数,填进 sockaddr_in 结构体
3. inet_ntoa
char *inet_ntoa(struct in_addr in);
- 参数:in 网络字节序 IP 结构体
- 返回值:点分十进制字符串 IP
- 作用:网络大端 IP,转成我们看得懂的
192.168.x.x字符串
五、UDP 套接字编程核心 API
1. socket 创建套接字
int socket(int domain, int type, int protocol);
- 参数
domain:AF_INET→ 使用 IPv4 地址族type:SOCK_DGRAM→ 数据报套接字,UDP 专用protocol:0,自动匹配协议
- 返回值:成功返回套接字文件描述符;失败 -1
- 作用:创建 UDP 通信端点
- 注意点:TCP 用
SOCK_STREAM;UDP 用SOCK_DGRAM - 比喻:拿到一个快递收发窗口
2. sockaddr_in IPv4 地址结构体
struct sockaddr_in
{
sa_family_t sin_family; //地址族:AF_INET
in_port_t sin_port; //端口,必须htons转换
struct in_addr sin_addr; //IP地址,inet_addr()转换
unsigned char sin_zero[8]; //补0占位
};
传参强制转成通用结构体
(struct sockaddr *)&sockaddr_in变量
3. bind 绑定端口
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
- 参数
sockfd:socket 返回 fdaddr:填好 IP 端口的 sockaddr_in,强转 struct sockaddr*addrlen:sizeof(struct sockaddr_in)
- 返回值:成功 0;失败 -1
- 作用:把套接字绑定本机端口,服务器必须 bind;客户端可以不 bind,系统自动分配随机端口
- 比喻:给自己快递窗口挂上端口门牌号,别人才能发包裹过来
4. sendto UDP 发送数据
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
- 参数
sockfd:udp 套接字 fdbuf:要发送数据缓冲区len:发送多少字节flags:一般填 0dest_addr:目标机器 IP + 端口结构体addrlen:目标地址结构体大小
- 返回值:成功返回实际发送字节数;失败 -1
- 作用:向指定 IP 端口发送 UDP 数据包
- 注意点:UDP 无连接,每次发送都要带上对方地址;不需要 connect
5. recvfrom UDP 接收数据
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
- 参数
sockfd:udp 套接字 fdbuf:接收缓冲区len:缓冲区最大字节flags:0 阻塞等待数据src_addr:输出参数,拿到发送方的 IP 端口addrlen:传入地址结构体大小,输出真实得到的地址长度(指针!)
- 返回值:成功收到多少字节;失败 -1
- 作用:接收 UDP 数据包,同时拿到是谁发过来的
- 注意点:
addrlen必须传指针,不能传普通变量
UDP 编程流程总结
UDP 服务器
socket(AF_INET, SOCK_DGRAM, 0)创建 udp 套接字- 填充
struct sockaddr_in本机 IP 端口 bind()绑定端口recvfrom()等待接收客户端消息sendto()回复消息- close 关闭 fd
UDP 客户端
socket()创建套接字- 填充目标服务器
sockaddr_in sendto()发送数据(客户端不用 bind,操作系统自动分配端口)recvfrom()接收服务器应答- close
UDP 没有 listen、accept、connect。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐



所有评论(0)