Linux下socket编程常用的数据格式转换函数

Linux下socket编程常常会进行数据格式转换,所以我就列出来一些常用的函数的使用方法、其作用等等

基础知识

啥是主机字节序?啥是网络字节序?

主机字节序指的是在特定计算机体系结构中多字节数据类型(就是字节数不为1的数据类型)在内存在存储的顺序

字节序两种顺序,一种是大端,一种是小端

大端模式 是低位字节存放在高地址,高位字节存放在低地址

通俗点讲就是如果有一个数组采用大端存储那么数组的第一个元素在一段内存的尾部,而数组的尾部却在那一段内存的头部

1
numbers[4] | 0x12 | 0x16 | 0x20 | numbers[0]

小端模式是低位字节存放在低地址,高位字节存放在高地址

与大端的相反,如果有一个数组采用小端存储那么数组的第一个元素在那一段内存的头部,数组的尾部在那段内存的尾部

1
numbers[0] | 0x12 | 0x16 | 0x20 | numbers[4]

主机字节序可能是大端可能是小端,但是小端的比较多,具体还是取决于计算机

网络字节序一般采用的都是大端

所以在传输数据是要进行字节序的转换

函数

本文中所有的函数需要导入<arpa/inet.h>头文件才能使用

1
#include <arpa/inet.h>

htons

将使用主机字节序的 uint16_t(unsigned int) 类型数据转换成使用网络字节序 uint16_t(unsigned int)

1
uint16_t htons(uint16_t hostshort);

示例

1
2
sockaddr_in addr = {0};
addr.sin_port = htons(8080);

htonl

将使用主机字节序的 uint32_t(unsigned int) 类型数据转换成使用网络字节序 uint32_t(unsigned int)

1
uint32_t htonl(uint32_t hostlong);

示例

1
2
3
sockaddr_in addr = {0};
uint32_t ip = inet_network("127.0.0.1");
addr.sin_addr.s_addr = htonl(ip);

ntohs

将使用网络字节序的 uint16_t(unsigned short int) 类型数据转换成使用主机字节序 uint16_t(unsigned short int)

1
uint16_t ntohs(uint16_t netshort);

示例

1
2
int clientfd = accept(sockfd,(sockaddr*)&addr,sizeof addr);
uint16_t port = ntons(addr.sin_port);

ntonl

将使用网络字节序的 uint32_t(unsigned int) 类型数据转换成使用主机字节序 uint32_t(unsigned int)

1
uint32_t ntohs(uint32_t netlong);

inet_addr

将十进制字符串格式的IPV4地址转换成网络字节序的二进制格式

转换成功则返回对应的网络字节序的二进制数据,如果转换出错返回 INADDR_NONE(通常为-1)

1
in_addr_t inet_addr(const char *cp);

示例

1
2
sockaddr_in addr = {0};
addr.sin_addr.s_addr = inet_addr("127.0.0.1");

inet_network

将十进制字符串格式的IPV4地址转换成二进制格式

注:返回的还是主机字节序不是网络字节序

转换成功则返回IPV4地址的二进制格式数据,转换失败则返回-1

1
in_addr_t inet_network(const char *cp);

示例

1
2
3
4
sockaddr_in addr = {0};
addr.sin_addr.s_addr = htonl(inet_network("127.0.0.1"));
// 因为 inet_network 函数只会将地址转换成二进制
// 所以需要 htonl 函数将其转换成网络字节序

inet_ntoa

将网络字节序的二进制数据转换成主机字节序的十进制字符串格式的IPV4地址

注:返回的指针是指向静态缓冲区的,后续的调用会覆盖该缓冲区

1
char *inet_ntoa(struct in_addr in);

示例

1
2
3
sockaddr_in addr = {0};
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
char *buffer = inet_ntoa(addr.sin_addr); // buffer = "127.0.0.1"

inet_pton

将主机字节序的十进制字符串格式的IP转换成网络字节序的二进制格式写入到dst中

如果成功转换并写入则返回 -1,如果src中的值为空则返回 0,如果af不是正确的地址族则返回 -1

1
2
#include <arpa/inet.h>
int inet_pton(int af, const char *src, void *dst);

af:使用的地址族

src:IP地址的字符串

dst:指向你要写入的那个缓冲区的指针

示例

1
2
3
sockaddr_in6 addr = {0};
inet_pton(AF_INET6,"2001:0db8:85a3:0000:0000:8a2e:0370:7334",&addr.sin6_addr);
// 将第二个参数转换成网络字节序的二进制格式写入到 addr.sin6_addr 中

inet_ntop

将网络字节序的二进制格式的IP地址 转换成主机字节序的十进制字符串格式写入到dst中

1
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);

af:使用的地址族

src:指向需要转换的IP地址的指针

dst:等待写入地址的字符串

size:地址的长度(用字节数表示)

示例

1
2
3
4
5
sockaddr_in addr = {0};
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
char data[16] = {0};
std::cout << "addr: " << inet_ntop(AF_INET, &addr.sin_addr, data, 16);
// 输出 127.0.0.1