大家好,这里是小缺,一名对嵌入式软件开发充满热情的探索者。这一篇文章主要内容是带大家了解网络编程中的字节序和地址转换。
1.1 字节序概述
字节序概念
字节序是指多字节数据在计算机内存中存储或者网络传输时各字节的存储顺序。
分类
小端格式:将低位字节数据存储在低地址
大端格式:将高位字节数据存储在低地址
在进行跨平台或网络数据传输时,由于不同系统可能采用不同的字节序,因此需要进行字节序的转换,以确保数据的正确性。在网络通信中,通常采用大端字节序作为标准,也称为网络字节序。
如何判断当前系统的字节序:
#include <stdio.h>
//判断当前系统的字节序
union un
{
int a;
char b;
};
int main(int argc, char const *argv[])
{
union un myun;
myun.a = 0x12345678;
printf("a = %#x\n", myun.a);
printf("b = %#x\n", myun.b);
if(myun.b == 0x78)
{
printf("小端存储\n");
}
else
{
printf("大端存储\n");
}
return 0;
}
运行结果
1.2 字节序转换函数
1、网络协议指定了通讯字节序—大端
2、只有在多字节数据处理时才需要考虑字节序
3、运行在同一台计算机上的进程相互通信时,一般不用考虑字节序
4、异构计算机之间通讯,需要转换自己的字节序为网络字节序
在需要字节序转换的时候一般调用特定字节序转换函数
host ‐‐> network
1 ‐‐ htonl
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostint32);
功能:
将32位主机字节序数据转换成网络字节序数据
参数:
hostint32:待转换的32位主机字节序数据
返回值:
成功:返回网络字节序的值
2 ‐‐ htons
#include <arpa/inet.h>
uint16_t htons(uint16_t hostint16);
功能:
将16位主机字节序数据转换成网络字节序数据
参数:
uint16_t:unsigned short int
hostint16:待转换的16位主机字节序数据
返回值:
成功:返回网络字节序的值
network ‐‐> host
3 ‐‐ ntohl
#include <arpa/inet.h>
uint32_t ntohl(uint32_t netint32);
功能:
将32位网络字节序数据转换成主机字节序数据
参数:
uint32_t: unsigned int
netint32:待转换的32位网络字节序数据
返回值:
成功:返回主机字节序的值
4 ‐‐ ntohs
#include <arpa/inet.h>
uint16_t ntohs(uint16_t netint16);
功能:
将16位网络字节序数据转换成主机字节序数据
参数:
uint16_t: unsigned short int
netint16:待转换的16位网络字节序数据
返回值:
成功:返回主机字节序的值
1.3 地址转换函数
在编程中,我们经常需要将点分十进制表示的IP地址(如"192.168.1.1")转换为整型数据,以便于在网络通信或者存储时使用。同样,我们也需要将整型数据转换为点分十进制表示的IP地址,以便于人类阅读和理解。
1.3.1 inet_pton()
字符串ip地址转整型数据
#include <arpa/inet.h>
int inet_pton(int family,const char *strptr, void *addrptr);
功能:
将点分十进制数串转换成32位无符号整数
参数:
family 协议族
AF_INET IPV4网络协议
AF_INET6 IPV6网络协议
strptr 点分十进制数串
addrptr 32位无符号整数的地址
返回值:
成功返回 1
失败返回 其它
案例:
#include <stdio.h>
#include <arpa/inet.h>
int main()
{
char ip_str[]="192.168.3.103";
unsigned int ip_int = 0;
unsigned char *ip_p = NULL;
//将点分十进制ip地址转化为32位无符号整形数据
inet_pton(AF_INET,ip_str,&ip_int);
printf("ip_int = %d\n",ip_int);
ip_p = (char *)&ip_int;
printf("in_uint = %d,%d,%d,%d\n",*ip_p,*(ip_p+1),*(ip_p+2),*(ip_p+3));
return 0;
}
运行结果
1.3.2 inet_ntop()
#include <arpa/inet.h>
const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);
这个函数声明了 inet_ntop
函数,它用于将32位无符号整数表示的IP地址转换为点分十进制字符串表示的IP地址。
family
:表示协议族,对于IPv4地址,使用AF_INET
,对于IPv6地址,使用AF_INET6
。addrptr
:指向要转换的32位无符号整数表示的IP地址的指针。strptr
:指向用于存储转换后的点分十进制字符串表示的IP地址的缓存区的指针。len
:缓存区的长度。对于IPv4地址,建议使用INET_ADDRSTRLEN
(其值为16)作为缓存区长度;对于IPv6地址,建议使用INET6_ADDRSTRLEN
(其值为46)作为缓存区长度。
函数的返回值是转换后的点分十进制字符串表示的IP地址的首地址。
如果转换成功,则返回字符串的首地址;
如果转换失败,则返回 NULL
。
案例
#include <stdio.h>
#include <arpa/inet.h>
int main()
{
unsigned char ip_int[]={192, 168, 3, 103};
char ip_str[16] = ""; //"192.168.3.103"
inet_ntop(AF_INET, &ip_int, ip_str, 16);
printf("ip_s = %s\n", ip_str);
return 0;
}
这段代码演示了如何使用 inet_ntop
函数将一个以字节数组形式存储的IP地址(IPv4)转换为点分十进制字符串形式。
执行结果
1.3.3 inet_addr()和inet_ntoa()
这两个函数只能用在ipv4地址的转换
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
in_addr_t inet_addr(const char *cp);
功能:将点分十进制ip地址转化为整形数据
参数:
cp:点分十进制的IP地址
返回值:
成功:整形数据
char *inet_ntoa(struct in_addr in);
功能:
将整形数据转化为点分十进制的ip地址
参数:
in:保存ip地址的结构体
返回值:
成功:点分十进制的IP地址