一、字节序核心原理
字节序是多字节数据在内存的存放顺序,仅影响 IP、端口整型数据,是 TCP/UDP 通信错乱的根本原因。
1. 主机字节序(小端)
电脑、开发板默认 小端序:低字节存低地址,字节颠倒存放。
例:端口 8080 = 0x1F90
内存存储:0x90 0x1F
本机 CPU 可正常识别,本地运行没问题,但不能直接发网络。
2. 网络字节序(大端)
TCP/IP 协议强制统一 大端序:高字节存低地址,字节正序存放。
网络标准字节:0x1F 0x90
核心矛盾
主机小端倒着存 ,网络大端正着传,不转换必然数值错乱。
不转换的错误后果
直接发送本机颠倒字节 0x90 0x1F
对方按大端解析:0x901F = 36911
原本 8080 端口,两端端口不匹配,直接连接失败。
3. TCP/UDP 标准收发流程(核心)
发送端:
本机小端颠倒字节 → htons/inet_aton 翻转1次(转正为网络大端) → 发送
接收端:
网络传来的是正序大端字节,小端 CPU 直接读会错乱;
++必须调用 ntohs 再翻转一次++,还原为本机正确数值。
终极一句话
发送翻一次转正、接收翻一次还原,两次翻转抵消大小端差异,通信数据才一致。
二、IP 转换函数(TCP/UDP 绑定/连接专用)
头文件
cs
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
结构体
cs
typedef uint32_t in_addr_t;
struct in_addr {
in_addr_t s_addr; // 存放网络字节序IP
};
1. inet_aton
int inet_aton(const char *cp, struct in_addr *inp);
功能:点分字符串IP → 网络字节序二进制IP
场景:TCP/UDP 的 connect、bind 填 IP 地址专用。
特点:内部自动字节序翻转,无需 htonl
2. inet_ntoa
char *inet_ntoa(struct in_addr in);
功能:网络字节序IP → 可读字符串IP
场景:打印客户端IP、日志输出调试。
IP 示例代码
cs
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
int main() {
struct in_addr in;
inet_aton("192.168.31.134",&in);
printf("IP:%s\n",inet_ntoa(in));
return 0;
}
三、端口转换函数(TCP/UDP 核心必用)
记忆:h主机 n网络 s16位端口 l32位整型
1. htons
uint16_t htons(uint16_t hostshort);
主机16位端口 → 网络大端端口
场景:给 sockaddr_in.sin_port 赋值(必须用)
2. ntohs
uint16_t ntohs(uint16_t netshort);
网络端口 → 主机端口
场景:接收对端端口、打印真实端口号
3. htonl / ntohl
32位整型字节序翻转,普通 TCP/UDP 开发不用,仅用于自定义协议。
四、TCP/UDP 开发避坑精华(必记)
-
端口只能用 htons / ntohs,不能用 32 位函数
-
inet_aton 自带网络字节序,禁止再套 htonl
-
端口不写 htons = 百分百端口错乱、连不上
-
发送转网络序,接收转主机序