Linux网络编程:IP地址字符串格式与in_addr格式的相互转换
目录
1.字符串格式转in_addr格式
2.in_addr格式转字符串格式
3.补充:IPv4地址和IPv6地址的结构体
在基于IPv4/IPv6的Socket网络编程中,通常会使用sockaddr_in/sockaddr_in6结构体进行网络通信,sockaddr_in结构体中的成员sin_addr表示32位的IP地址,sockaddr_in6结构体中的成员sin6_addr表示128位的IP地址,这些都是in_addr格式的IP地址。但是我们通常使用点分十进制表示IP地址,而使用in_addr格式的IP地址比较复杂。
因此操作系统为我们提供了IP地址转换函数:支持IP地址在点分十进制字符串格式和in_addr格式的IP地址之间相互转换。
1.字符串格式转in_addr格式
int inet_pton(int af, const char *src, void *dst);
#include <arpa/inet.h>
int inet_pton(int af, const char *src, void *dst);
af:地址族,指定要转换的地址类型(AF_INET表示IPv4地址,AF_INET6表示IPv6地址)
src:指向包含点分十进制格式IP地址字符串的指针
dst:指向转换成功后存储IP地址的缓冲区的指针(IPv4地址下为struct in_addr结构体,IPv6地址下位struct in6_addr结构体)
返回值:成功返回1,失败返回-1并设置errno错误码(如果src不是有效的IP地址,返回0)
示例代码(IPv4地址):
#include <iostream>
#include <arpa/inet.h>
//IPv4地址
void test()
{
//int inet_pton(int af, const char *src, void *dst);
const char* ip_str="127.0.0.1";//字符串格式IP地址
struct in_addr ip_bin;//in_addr格式IP地址
int result=inet_pton(AF_INET,ip_str,&ip_bin);
if(result==1)
std::cout<<"转换成功,in_addr格式IP地址为:"<<ip_bin.s_addr<<std::endl;
else if(result==0)
std::cout<<"无效IP地址"<<std::endl;
else
std::cerr<<"转换失败"<<std::endl;
}
int main()
{
test();
return 0;
}
2.in_addr格式转字符串格式
const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
#include <arpa/inet.h>
const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
af:地址族,指定要转换的地址类型(AF_INET表示IPv4地址,AF_INET6表示IPv6地址)
src:指向存储网络字节序IP地址的缓冲区(IPv4地址下是指向struct in_addr的指针,IPv6地址下是指向struct in6_addr的指针)
dst:指向存储点分十进制字符串形式的IP地址缓冲区的指针
cnt:dst缓冲区的大小,单位为字节
返回值:成功返回只想dst的指针,失败返回NULL并设置errno错误码
示例代码:
//IPv4地址
void test()
{
//const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
struct in_addr ip_bin;
ip_bin.s_addr=0x01020304;//假设存在一个in_addr格式的IPv4地址:1.2.3.4
ip_bin.s_addr=htonl(ip_bin.s_addr);//要先将主机字节序IP地址转换为网络字节序IP地址
char ip_str[1024];
const char* result=inet_ntop(AF_INET,&ip_bin,ip_str,sizeof(ip_str));
if(result==nullptr)
std::cout<<"转换失败"<<std::endl;
else
std::cout<<"转换成功,点分十进制字符串格式IP地址为:"<<ip_str<<std::endl;
}
int main()
{
test();
return 0;
}
3.补充:IPv4地址和IPv6地址的结构体
IPv4地址结构体
struct sockaddr_in {
sa_family_t sin_family; // 地址族,通常为 AF_INET 表示 IPv4
uint16_t sin_port; // 端口号,使用网络字节序
struct in_addr sin_addr; // IPv4 地址,使用网络字节序
char sin_zero[8]; // 填充字段,用于使结构体大小与 sockaddr 一致
};
struct in_addr {
uint32_t s_addr; // IPv4地址,以网络字节序存储
};
IPv6地址结构体
struct sockaddr_in6 {
sa_family_t sin6_family; // 地址族,通常为 AF_INET6 表示 IPv6
uint16_t sin6_port; // 端口号,使用网络字节序
uint32_t sin6_flowinfo; // 流信息,通常设置为0
struct in6_addr sin6_addr; // IPv6 地址,使用网络字节序
uint32_t sin6_scope_id; // 作用域标识,用于链路本地地址等
};
struct in6_addr {
uint8_t s6_addr[16]; // IPv6地址,以网络字节序存储
};