首页 > 技术文章 > Linux网络编程-2-大小端及IP地址转换相关函数

cxl- 2021-08-12 22:57 原文

大端 & 小端

大小端之定义

计算机系统是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。

在几乎所有的机器上,对于跨越多字节的程序对象,往往都是被连续存储的,对象的地址为所使用的字节中最小的地址。

在多字节的程序对象中,对不同的字节有两种排列方式:大端和小端。(大小端之争就如打鸡蛋从大头打还是从小头打,没有实际意义。大小端的起源也是这个,狗头)

大端模式:是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中。(高地址存低位

小端模式:是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中。(高地址存高位,对应到内存中读是个反的

假如32位宽(uint32_t)的数据0x12345678,从地址0x08004000开始存放:

地址 小端存放内容 大端存放内容
0x08004003(高地址) 0x12 0x78
0x08004002 0x34 0x56
0x08004001 0x56 0x34
0x08004000(低地址) 0x78 0x12

大小端之实例

判断本机大小端的方法:

#include <stdio.h>
void byteorder()
{
	union
	{
		short value;
		char union_bytes[ sizeof( short ) ];
	} test;
	test.value = 0x0102;
	if (  ( test.union_bytes[ 0 ] == 1 ) && ( test.union_bytes[ 1 ] == 2 ) )
	{
		printf( "big endian\n" );
	}
	else if ( ( test.union_bytes[ 0 ] == 2 ) && ( test.union_bytes[ 1 ] == 1 ) )
	{
		printf( "little endian\n" );
	}
	else
	{
		printf( "unknown...\n" );
	}
}

int main() {
	byteorder();
}

大端模式:Sun、PowerPC、IBM

小端模式:x86、DEC

ARM既可以工作在大端模式,也可以工作在小端模式,取决于特定的操作系统。该芯片常用的操作系统Android和iOS采用小端模式。

大小端与网络编程

为了解决大小端机子之间通信时存在的问题,在网络编程中也有个字节序的概念:

网络字节序:大端模式(高地址存低位)

主机字节序:小端模式(高地址存高位)

发送端总是把要发送的数据转化成大端字节序数据后再发送,而接收端知道传送的数据是大端字节序,可以根据自身的字节序来决定是否转换。

字节序转换函数:

#include <netinet/in.h>
//h 指代 host(主机),n 指代 net(网络),l 是 long,s 是 short 
unsigned long int htonl(unsigned long int hostlong);
unsigned short int htons(unsigned short int hostshort);
unsigned long int ntohl(unsigned long int netlong);
unsigned short int ntohs(unsigned short int netshort);

IP地址转换函数

IP地址实际上是一个uint32_t的整数,将每一个字节读成一个十进制数,并加点区分便是点分十进制(127.0.0.1),这是我们通常所见的IP地址表示方法。但是点分十进制是一个字符串,对于计算机来说,它是不好识别的。所以需要涉及到点分十进制和uint32_t的转换。

#include <arpa/inet.h>

//点分十进制转换成二进制
in_addr_t inet_addr(const char* strptr);		//失败返回INADDDR_NONE
int inet_aton(const char* cp, struct in_addr* inp);		//这个函数将转换结果存储结构体中,而不是返回。成功时返回1,失败返回0

//二进制转换为点分十进制
char* inet_ntoa(struct in_addr in);		//该函数内存用一个静态变量存储转化结构,且不可重入

当然,下面这对更新函数也能完成和前面3个函数同样的功能,并同时适用IPv4和IPv6

#include <arpa/inet.h>
int inet_pton(int af, const char* src, void* dst);		//成功返回1,失败返回0并设置errno
const char* inet_ntop(int af, const void* src, char* dst, socklen_t cnt);		//成功返回指向目标存储单元的地址,失败则返回NULL并设置errno

reference

[1] 深入理解计算机系统

[2] Linux高性能服务器编程

推荐阅读