一、网络通信的底层逻辑:协议栈与封装
数据如何传输?通过分层协作实现。就像快递送货,每层只负责特定环节,不越界。
1. Linux 网络协议栈分层
- 应用层:给数据定格式,如 HTTP、SSH、FTP。
- 传输层:给数据标进程,用端口号区分程序(如 80 端口是浏览器),核心是 TCP 和 UDP。
- 网络层:给数据标主机,用 IP 地址定位目标电脑。
- 数据链路层:给数据标节点,用 MAC 地址在局域网内传输。
- 物理层:纯硬件传输,如网线传电信号、光纤传光信号。
在 Socket 网络编程(IPv4 场景)中,sockaddr_in结构体的 sin_addr字段以 32 位二进制形式存储 IP 地址,但日常习惯用点分十进制字符串表示,因此需要借助地址转换函数实现互转。
地址转换函数
需引入头文件 <arpa/inet.h>。
1. 字符串转 in_addr
inet_aton(const char *strptr, struct in_addr *addrptr):将点分十进制字符串转为 in_addr 结构体,成功返回 1,失败返回 0。inet_addr(const char *strptr):直接返回转换后的 32 位整数形式 IP,无法区分转换失败与 0.0.0.0。inet_pton(int family, const char *strptr, void *addrptr):更通用的函数(支持 IPv4/IPv6),family 传 AF_INET 表示 IPv4。
2. in_addr 转字符串
inet_ntoa(struct in_addr inaddr):将 in_addr 结构体转为点分十进制字符串,但返回的是静态缓冲区,多线程场景下可能被覆盖。inet_ntop(int family, const void *addrptr, char *strptr, size_t len):更安全的通用函数,需手动传入缓冲区存储结果,避免线程安全问题。

2. 数据封装与解封装
发送方流程:应用层生成原始数据 -> 传输层加头(源/目的端口)变成报文段 -> 网络层加头(源/目的 IP)变成数据报 -> 数据链路层加头和尾(MAC 地址)变成以太网帧 -> 物理层变成电信号发送。 接收方反向操作:拆帧 -> 拆数据报 -> 拆报文段 -> 拿到原始数据。
以下展示 C++ 网络编程中封装 IP 与端口处理的 InetAddr 类代码示例:
#include <arpa/inet.h>
#include <string>
#include <cstdint>
#include <cstring>
{
:
( sockaddr_in& addr) : _addr(addr) {
_port = (addr.sin_port);
_ip = (addr.sin_addr);
}
( std::string& ip, port) : _ip(ip), _port(port) {
(&_addr, , (_addr));
_addr.sin_family = AF_INET;
_addr.sin_port = (port);
(AF_INET, ip.(), &_addr.sin_addr);
}
{ _port; }
{ _ip; }
& () { _addr; }
:
_addr;
std::string _ip;
_port;
};






