字节序转换函数
计算机中读取数据是从低地址往高地址读取的
计算机中多字节整数序列的存储有2种方式:
- 小端存储(小端字节序):低序字节存储在低地址
- 大端存储(大端字节序):高序字节存储在低地址
主机字节序(Host Byte Order):不同主机存储方式不同,可能大端存储也可能小端存储。
网络字节序(Network Byte Order):网络字节序是大端字节序。
htonl | htons
(h)主机字节序 ——> (n)网络字节序
头文件:
#include <arpa/inet.h>(有些系统采用#include <netinet/in.h>)
原型:
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
参数:
uint32_t hostlong:32位主机字节序(4字节);
uint16_t hostshort:16位主机字节序(2字节);
返回值:
返回转换后的网络字节序;
例程:
//端口号宏定义
#define PORT 8888
htons(PORT);
//端口号局部定义
unsigned short port = 8888;
htons(port);
//外部传参方式获取端口号
htons(*(unsigned short*)argv[2]);//也可以用atoi函数转换类型
C
ntohl | ntohs
(n)网络字节序 ——> (h)主机字节序
头文件:
#include <arpa/inet.h>
原型:
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
参数:
uint32_t hostlong:32位网络字节序(4字节);
uint16_t hostshort:16位网络字节序(2字节);
返回值:
返回转换后的主机字节序;
例程:
ntohs(caddr.sin_port);//获取与客户端通信的端口号
C
IP地址(二进制、点分十进制转换)
IP地址在网络字节序中需以二进制传输
点分十进制 ——> 二进制(网络字节序)
inet_aton
只适用于IPv4
a:表示ascii串;n:表示numeric数值
头文件:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
原型:
int inet_aton(const char *cp, struct in_addr *inp);
参数:
char *cp:源IP字符串,如 “192.168.1.104”;
struct in_addr *inp:存储struct in_addr的指针;
typedef uint32_t in_addr_t;
struct in_addr {
in_addr_t s_addr;//IP地址的网络字节序值
};
返回值:
成功,返回1;
失败,返回0,不更新errno;
例程:
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(*(unsigned short*)argv[2]);
inet_aton(argv[1],&saddr.sin_addr);
//inet_pton(AF_INET,argv[1],&saddr.sin_addr.s_addr);
//saddr.sin_addr.s_addr = inet_addr(argv[1]);
C
inet_pton
可用于IPv4和IPv6
p表示:地址的表达presentation
头文件:
#include <arpa/inet.h>
原型:
int inet_pton(int af, const char *src, void *dst);
参数:
int af:协议族
AF_INET :IPv4
AF_INET6:IPv6
char *src:源IP字符串的地址 “192.168.1.104”;
void *dst:存储in_addr_t的指针
int af是AF_INET
typedef uint32_t in_addr_t;
struct in_addr{
in_addr_t s_addr;
};
int af是AF_INET6
struct in6_addr;
返回值:
成功,返回1;
af字符串格式错误,返回0;
出错,返回-1,更新errno;
例程:
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(*(unsigned short*)argv[2]);
//inet_aton(argv[1],&saddr.sin_addr);
inet_pton(AF_INET,argv[1],&saddr.sin_addr.s_addr);
//saddr.sin_addr.s_addr = inet_addr(argv[1]);
C
inet_addr
只适用于IPv4
不能转换255.255.255.255;返回值为-1,与错误时返回-1重合了,无法区分
头文件:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
原型:
in_addr_t inet_addr(const char *cp);
参数:
char *cp:源IP字符串的地址 “192.168.1.104”;
返回值:
成功,返回转换后的网络字节序ip:in_addr_t
typedef uint32_t in_addr_t;
struct in_addr {
in_addr_t s_addr;
};
失败,返回-1;
例程:
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(*(unsigned short*)argv[2]);
//inet_aton(argv[1],&saddr.sin_addr);
//inet_pton(AF_INET,argv[1],&saddr.sin_addr.s_addr);
saddr.sin_addr.s_addr = inet_addr(argv[1]);
C
二进制 ——> 点分十进制
inet_ntoa
只适用于IPv4
转换后的字符串是存储在静态存储区,下次调用该函数,会把上次的数据覆盖。所以最好保存函数返回的数据;
头文件:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
原型:
char *inet_ntoa(struct in_addr in);
参数:
struct in_addr in:存储网络字节序的结构体;
typedef uint32_t in_addr_t;
struct in_addr {
in_addr_t s_addr;
};
返回值:
成功,返回点分十进制的字符串的首地址;
失败,返回NULL;
例程:
printf("收到来自[%s]客户端的请求信息",inet_ntoa(caddr.sin_addr));
//char dst[N] = "";
//printf("收到来自[%s]客户端的请求信息",inet_ntop(AF_INET,&caddr.sin_addr.s_addr,dst,N));
C
inet_ntop
可用于IPv4和IPv6
头文件:
#include <arpa/inet.h>
参数:
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
参数:
int af:协议族
AF_INET :IPv4
AF_INET6:IPv6
void *src:存储着in_addr_t的指针
int af是AF_INET
typedef uint32_t in_addr_t;
struct in_addr{
in_addr_t s_addr;
};
int af是AF_INET6
struct in6_addr;
char *dst:存储转换后的点分十进制字符串;
socklen_t size:缓冲区大小,其实就是指定多大的空间用于转换ip;
返回值:
成功,返回字符串的首地址,就是dst的首地址;
失败,返回NULL,更新errno;
例程:
//printf("收到来自[%s]客户端的请求信息",inet_ntoa(caddr.sin_addr));
char dst[N] = "";
printf("收到来自[%s]客户端的请求信息",inet_ntop(AF_INET,&caddr.sin_addr.s_addr,dst,N));
C
域名转换(域名 ——> IP地址)
gethostbyname
头文件:
#include <netdb.h>
原型:
struct hostent *gethostbyname(const char *name);
参数:
char *name:域名字符串首地址
返回值:
成功,返回结构体struct hostent *:
struct hostent {
char *h_name; /* official name of host */正式主机名
char **h_aliases; /* alias list */主机别名
int h_addrtype; /* host address type */主机IP地址族类型
int h_length; /* length of address */主机IP地址长度
char **h_addr_list; /* list of addresses */主机绑定的IP地址列表
};
出错,返回NULL,设置h_errno;
例程:
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
int main(int argc, const char *argv[])
{
if(argc < 2)
{
printf("请输入域名\n");
return 0;
}
struct hostent *host = gethostbyname(argv[1]);
if(host==NULL)
{
printf("获取IP地址失败,result: %s\n",hstrerror(h_errno));
return -1;
}
int i;
//官方域名
printf("Official: %s\n",host->h_name);
//别名
for(i=0; host->h_aliases[i]; i++){
printf("Aliases %d: %s\n", i+1, host->h_aliases[i]);
}
//地址类型
printf("Address type: %s\n", (host->h_addrtype==AF_INET) ? "AF_INET": "AF_INET6");
//IP地址
for(i=0; host->h_addr_list[i]; i++){
printf("IP addr %d: %s\n", i+1, inet_ntoa( *(struct in_addr*)host->h_addr_list[i] ) );
}
return 0;
}
结果:
$ ./a.out shengto.top
Official: shengto.top
Address type: AF_INET
IP addr 1: 121.199.62.148
$ ./a.out video2020.shengto.top
Official: video2020.shengto.top.w.kunlungr.com //CDN服务
Aliases 1: video2020.shengto.top //访问主机别名,其实真正访问的是正式主机名
Address type: AF_INET
IP addr 1: 114.80.187.72
C
本文链接:https://shengto.top/network_programming/inet_converts.html
转载时须注明出处及本声明