-
2021-12-14 18:21:10
什么是字节序?
字节序就是数据存放的顺序。当数据仅有1字节时,计算机无需考虑字节存放顺序;但当数据大于1字节时,就必须考虑如何存放了(先放高字节还是低字节),如十六进制数
0x12345678
,按人类阅读习惯,左起为高字节,右起为低字节:|高字节--------------->低字节| |------|------|------|------| | 0x12 | 0x34 | 0x56 | 0x78 | |------|------|------|------|
即
0x12
为高字节,0x78
为低字节。内存地址连续排列,十六进制数
0x12345678
占用4字节,在不同体系架构下,数据存放方式略有差异,分为大端字节序和小端字节序。大端序
符合人的阅读习惯,低字节存放在高地址,高字节存放在低地址,即内存排布如下:
|高字节--------------->低字节| |------|------|------|------| | 0x12 | 0x34 | 0x56 | 0x78 | |------|------|------|------| |低地址--------------->高地址|
小端序
低字节存放在低地址,高字节存放在高地址,即内存排布如下:
|低字节--------------->高字节| |------|------|------|------| | 0x78 | 0x56 | 0x34 | 0x12 | |------|------|------|------| |低地址--------------->高地址|
什么时候需要关注字节序?
普遍场景是网络编程有数据交互时,网络字节序统一为大端序,而大多x86机器为小端序,此时就需要字节序转换(只在必要时转换,如
socket端口号
,无需所有数据都转一遍),如果程序只是在机器本地运行则一般不考虑。运行时判断机器字节序
以下分别通过指针和共用体判断字节序
#include <stdio.h> /** \brief 通过指针操作判断机器字节序是否为小端序 * * \return 小端序返回1,大端序返回0 * */ int is_little_endian(void) { int data= 1;//用1可移植性更好,int为4字节时等价于0x00000001 //printf("data 0x%08x in memory\n", data); //printf("first byte data is : 0x%08x\n", *(char *)&data); /**< 低字节放在低地址,低地址即data变量首地址,即小端序 */ if(1 == *(char *)&data) { return 1; } else { return 0; } } /** \brief 通过共用体判断机器字节序是否为小端序 * * \return 小端序返回1,大端序返回0 * */ int is_little_endian_2() { union endian { int i; char ch; }; union endian test; test.i=1;//int为4字节时等价于0x00000001 //printf("data 0x%08x in memory\n", test.i); //printf("first byte data is : 0x%08x\n", test.ch); if(1 == test.ch) { return 1; } else { return 0; } }
自定义字节序转换方法
原理就是根据数据的位数进行移位操作,示例:32位整数的转换
/** \brief 32位整数大小端转换,仅在小端时转换,使用了前面定义的is_little_endian()函数 */ #define L2B_32(data) (1 == is_little_endian() ? (( (data & 0xff000000) >>24) | \ ((data & 0x00ff0000) >>8) | \ ((data & 0x0000ff00) <<8) | \ ((data & 0x000000ff) <<24) ) \ : data )
对比两种字节序可以发现无非就是:高字节移动到低字节,低字节移动到高字节
假设小端字节序保存的数据为
0x12345678
,即| 0x12 | 0x34 | 0x56 | 0x78 |
,转换为大端的结果为
| 0x78 | 0x56 | 0x34 | 0x12 |
,0x78
向左移动了3个字节即24位0x56
向左移动了1个字节即8位同理:
0x34
向右移动了1个字节即8位0x12
向左移动了3个字节即24位L2B_32(data)
宏定义用了三目运算符? :
,实现当判断机器为小端字节序时自动做转换,判断机器为大端时不做转换。以上示例实现了int的字节序转换,short、long long等类型操作类似,不再赘述。
验证
以下测试程序使用x86机器运行
int main() { printf("%#x\n", L2B_32(0x12345678)); return 0; }
运行结果
0x78563412
更多相关内容 -
大小端字节序转换
2022-04-24 15:55:19二、字节序转换函数 头文件:#include <arpa/inet.h> ①htonl函数(发送数据方使用) 32位:(IPv4字节序的转换) uint32_t htonl(uint32_t host32bitvalue); 功能:将32位主机字节序数据转换成网络字节序...特点
①各主机的字节序可能不同,网络协议指定的通讯字节序为大端。
②只有在多字节数据处理时才需要考虑字节序。
③运行在同一台计算机的进程互相通信时,不需要考虑字节序。二、字节序转换函数
头文件:
#include <arpa/inet.h>
①htonl函数(发送数据方使用)32位:(IPv4字节序的转换)
uint32_t htonl(uint32_t host32bitvalue);
功能:将32位主机字节序数据转换成网络字节序数据。
返回值:返回网络字节序的值。②ntohl函数(接收数据方使用)
uint32_t ntohl(uint32_t net32bitvalue); //返回主机字节序的值
功能:将32位网络字节序转换成主机字节序数据。
返回值:返回主机字节序的值。16位(端口的转换)
③htons函数(发送方使用)
uint16_t htons(uint16_t host16bitvalue); //返回网络字节序的值
功能:将16位主机字节序数据转换成网络字节序数据。
返回值:返回网络字节序的值。
④ntohs函数(接收方使用)uint16_t ntohs(uint16_t net16bitvalue); //返回主机字节序的值
功能:将16位网络字节序转换成主机字节序数据。
返回值:返回主机字节序的值。总结:四个函数,如果主机和网络字节序相同,那么函数不会颠倒数据
二、新型网路地址转化函数
这两个函数是随IPv6出现的函数,对于IPv4地址和IPv6地址都适用,函数中p和n分别代表表达(presentation)和数值(numeric)。地址的表达格式通常是ASCII字符串,数值格式则是存放到套接字地址结构的二进制值。
① 将点分十进制的ip地址转化为用于网络传输的数值格式
int inet_pton(int family, const char *strptr, void *addrptr); 参数:family 协议族 strptr 点分十进制数串 addrptr 32位无符号整数的地址 返回值:若成功则为1,若输入不是有效的表达式则为0,若出错则为-1
eg:
#include <stdio.h> #include <arpa/inet.h> int main() { //点分十进制数串 char *str_ip="172.20.10.1"; //32位无字符串整型数据 unsigned int num_ip=0; //AF_INET:IPv4 AF_INET6:IPv6 inet_pton(AF_INET,str_ip,&num_ip); printf("转换前:str_ip=%s\n",str_ip); printf("转换后:num_ip=%u\n",num_ip); return 0; }
②将数值格式转化为点分十进制的ip地址格式
const char * inet_ntop(int family, const void *addrptr, char *strptr, size_t len); 返回值:若成功则为指向结构的指针,若出错则为NULL
eg:
#include <stdio.h> #include <arpa/inet.h> int main() { //模拟一个32位网络字节序IP地址 unsigned char p[]={192.168.0.1}; char ip_str[16]=""; inet_ntop(AF_INET,p,ip_str,16); printf("ip_str:%s\n",ip_str); return 0; }
-
字节序转换&IP地址转换接口
2022-03-28 10:53:121.字节序转换接口: 2.字符串点分十进制IP地址转换为网络字节序整数IP地址接口: 3.将网络IP地址转换为字符串点分十进制IP地址: 常用命令
数据经过网络传输就需要考虑字节序的问题,经常常需要针对网络字节序(大端)和主机字节序进行转换。1.字节序转换接口:
//man hton 可查看 #include <arpa/inet.h> h:host n: net uint32_t htonl(uint32_t hostlong); 32位(4字节)主机字节序到网络字节序的转换。 uint16_t htons(uint16_t hostshort); 16位主机字节序到网络字节序的转换 uint32_t ntohl(uint32_t netlong); 32网络字节序到位主机字节序转换 uint16_t ntohs(uint16_t netshort); 16位网络字节序到位主机字节序转换 //上面这些接口里面能判断主机字节序,若与要转换的相同则不操作返回。
2.字符串点分十进制IP地址转换为网络字节序整数IP地址接口:
eg:192.168.2.2-转为十进制数字地址0xcoa80202
#include <sys/socket.h> //socket接口头文件 #include <netinet/in.h> //地址结构,协议类型头文件 #include <arpa/inet.h> //字节序转换接口头文件 in_addr_t inet_addr(const char *cp);只能转换IPV4的ip地址 eg: addr.sin_addr.s_addr = inet_addr("172.17.0.3"); //int inet_pton(int af, const char *src, void *dst); IPV4,ipv6都能转换。
3.将网络IP地址转换为字符串点分十进制IP地址:
char *inet_ntoa(struct in_addr in); 只能转换IPV4的ip地址 //const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);IPV4,ipv6都能转换。 IPV4,ipv6都能转换。
Eg:
bool Accept(TcpSocket *sock, std::string *ip = NULL,uint16_t *port = NULL){ //int accept(监听描述符,获取客户端地址,长度) struct sockaddr_in addr; socklen_t len = sizeof(struct sockaddr_in); int newfd = accept(_sockfd,(sockaddr*)&addr,&len); if (newfd < 0) { perror("accept error"); return false; } sock->_sockfd = newfd; if (ip != NULL) { *ip = inet_ntoa(addr.sin_addr); } if (port != NULL) { *port = ntohs(addr.sin_port); } return true; }
常用命令
netstat -anptu 可查看当前主机上网络状态信息
命令: netstat -a 查看所有网络信息 -n 不显示服务名称,显示地址信息 -P 显示服务进程 -t 过滤,只包含TCP -u 过滤,只包含udp
Ifconfig 可查看地址信息
云服务器–>内网地址:
-
Java整型数与网络字节序byte[]数组转换关系详解
2020-08-29 13:31:51主要介绍了Java整型数与网络字节序byte[]数组转换关系,结合实例形式归纳整理了java整型数和网络字节序的byte[]之间转换的各种情况,需要的朋友可以参考下 -
c/c++字节序转换
2019-04-04 18:28:15字节序(byte order)关系到多字节整数(short/int16、int/int32,int64)和浮点数的各字节在内存中的存放顺序。字节序分为两种:小端字节序(little endian)和大端字节序(bigendian)。小端字节序:低字节存放在...字节序(byte order)关系到多字节整数(short/int16、int/int32,int64)和浮点数的各字节在内存中的存放顺序。字节序分为两种:小端字节序(little endian)和大端字节序(big endian)。小端字节序:低字节存放在内存低地址,例如对两字节整数0x0100(十进制数256),低字节00放在低地址(假设地址为0x0041f880),高字节01放在高地址0x0041f881。大端字节序:高字节在低地址,同样是0x0100,高字节01放在低地址(假设地址为0x0041f880),低字节00放高地址0x0041f881。可见对相同的两字节整数,在不同字节序的机器上其内存布局是不同的,反过来内存布局相同的,在不同字节序的机器上被解释为不同的整数值,除非这几个字节值相同。
字节序是由cpu处理器架构决定的,和操作系统无关,例如Intel cpu采用小端字节序,PowerPC采用大端字节序,有些cpu例如Alpha支持两种字节序,但在使用时要设置具体采用哪一种字节序,不可能同时用两种。主机字节序(host byte order)就是指当前机器的字节序,根据cpu处理器的架构和设置,主机字节序可为小端字节序或大端字节序。关于字节序问题,较全面的描述见https://en.wikipedia.org/wiki/Endianness。
在socket网络编程中通常会涉及到多字节整数、浮点数的传输,如果两台机器字节序不同,直接传多字节整数或浮点数会导致双方将这些多字节解释成不同的数字,所以要在网络协议中规定编解码方式,例如有的协议将整数编码成字符串来避免字节序问题,但只要协议中有多字节整数,都要规定采用什么字节序来表示协议中的多字节整数(除非能保证两台机器的字节序是相同的),也就出现了网络字节序,网络字节序其实就是大端字节序,协议当然也可采用小端字节序,只要双方统一就行。
如上所述,在设计网络二进制协议时,对多字节整数,要规定打包传输时的字节序:网络字节序还是小端字节序。客户端和服务器代码在打包和解包时,对多字节整数,要进行主机字节序和协议规定的字节序的相互转化。
Java应用通常使用java.nio.ByteBuffer进行协议数据的打包和解包,其order(ByteOrder bo)方法可设置打包或解包使用的字节序;如果使用netty框架,可使用ByteBuf类的order方法。
C/C++应用通常使用C库中的如下函数来进行主机字节序和网络字节序的相互转换。
// hton* 主机字节转网络字节序
uint64_t htonll(uint64_t hostlonglong);
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
// ntoh* 网络字节序转主机字节序
uint64_t ntohll(uint64_t hostlonglong);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
linux系统在endian.h头文件中提供了更多的函数进行主机字节和大小端字节序的相互转换,如下:
uint16_t htobe16(uint16_t host_16bits);
uint16_t htole16(uint16_t host_16bits);
uint16_t be16toh(uint16_t big_endian_16bits);
uint16_t le16toh(uint16_t little_endian_16bits);
uint32_t htobe32(uint32_t host_32bits);
uint32_t htole32(uint32_t host_32bits);
uint32_t be32toh(uint32_t big_endian_32bits);
uint32_t le32toh(uint32_t little_endian_32bits);
uint64_t htobe64(uint64_t host_64bits);
uint64_t htole64(uint64_t host_64bits);
uint64_t be64toh(uint64_t big_endian_64bits);
uint64_t le64toh(uint64_t little_endian_64bits);
htobe*(例如htobe16)表示主机字节序到大端字节序(网络字节序);htole*表示主机字节序到小端字节序;be*toh表示大端到主机;le*toh表示小端到主机。
上面的字节序转换函数有个缺点,就是方法太多不方便使用,需要根据多字节整数的类型(uint16_t/int16_t/uint32_t/int32_t/uint64_t/int64_t)来调用不同的转换函数,所以在c++应用中利用模板技术编写了4个统一的字节序转换函数,和整数的类型无关。如下:
/* * ByteOrderUtil.h * * Created on: Nov 15, 20xx * Author: wanshi */ #ifndef BYTEORDERUTIL_H_ #define BYTEORDERUTIL_H_ #include <stdint.h> namespace ByteOrder { const uint16_t us_flag = 1; // little_end_flag 表示主机字节序是否小端字节序 const bool little_end_flag = *((uint8_t*)&us_flag) == 1; //小端到主机 template<typename T> T le_to_host(T& from) { T to; uint8_t byteLen = sizeof(T); if(little_end_flag){ return from; } else{ char* to_char = (char*)&to; char* from_char = (char*)&from; for(int i=0;i<byteLen;i++){ to_char[i] = from_char[byteLen-i-1]; //此处也可用移位操作来实现 } return to; } } //主机到小端 template<typename T> T host_to_le(T& from) { return le_to_host(from); } //大端到主机 template<typename T> T be_to_host(T& from) { T to; uint8_t byteLen = sizeof(T); if(!little_end_flag){ return from; } else{ char* to_char = (char*)&to; char* from_char = (char*)&from; for(int i=0;i<byteLen;i++){ to_char[i] = from_char[byteLen-i-1]; //此处也可用移位操作来实现 } return to; } } //主机到大端 template<typename T> T host_to_be(T& from) { return be_to_host(from); } } #endif /* BYTEORDERUTIL_H_ */ 使用演示: #include "ByteOrderUtil.h" using namespace ByteOrder; int main(int argc,char** argv) { uint16_t u16t = 0x1514; //host到小端 uint16_t leu16t = host_to_le(u16t); uint16_t hu16t = le_to_host(leu16t); uint64_t u64t = 0x15141312; //host到大端 uint64_t beu64t = host_to_be(u64t); uint64_t hu64t = be_to_host(beu64t); return 0; }
-
double类型数据的网络字节序转换
2019-06-02 22:57:40最近,需要将一套linux开发程序移植到另外一块开发板上,程序中涉及到了网络通信,且所用开发板的处理器为大端模式,之前为小端模式,因此在数据传输的过程中需要考虑到大小端转换的问题。 全新的界面设计 ,将会... -
大小端与字节序转换
2020-08-26 11:25:03大端小端 不同机器内部对变量的字节存储顺序不同,有的采用大端...大端字节序:高位字节在前,低位字节在后,这是人类读写数值的方法。 小端字节序:低位字节在前,高位字节在后,即以0x1122形式储存。 0x1234567的大 -
long long类型的主机字节序和网络字节序转换
2020-05-21 15:19:361. 网络字节序和主机字节序 在网络编程中经常会碰到网络字节序和主机字节序。关于网络字节序和主机字节序在学习前需要理解以下几个概念。 字节序,指的是字节在内存中存储的顺序,比如一个int32_t类型的数值占用4个... -
主机字节序和网络字节序转换函数
2019-05-12 14:28:06#include <arpa/inet.h> uint32_t htonl(uint32_t hostlong);<主机字节序转换位网络字节序32,转换IP地址时...主机字节序16位转换为网络字节序16位,转换端口时用> uint32_t ntohl(uint32_t netlong);&... -
IP、主机字节序、网络字节序、互转
2017-01-05 11:48:12IP、主机字节序、网络字节序、互转 ------------------------------------------------------- using System;... Console.WriteLine("网络字节序转换IP后值为:{0}", ss); Console.ReadKey(); } } } -
字节序转换详解
2019-10-18 12:09:11在跨平台和网络编程中我们经常会提到网络字节序和主机字节序,如果没有正确对两者进行转换,从而导致两方产生了不同的解释,就会出现意想不到的bug。 目录 0x01 概念 0x02 分类 0x03 两种字节序之间的区别 0x01 ... -
为啥要发生字节序转换 ? ? ?
2021-06-03 23:45:07很显然为了防止出现这种情况,所以我们这里要引入字节序转换这个概念. 原理 接口认识 这就是在实现网络数据传输之前必须要的字节序转换的过程,上面是一些常用的接口,大家自行使用. ... -
网络字节序转换函数
2020-07-28 09:15:27文章目录1 网络字节序转换函数 1 网络字节序转换函数 常用的网络字节序转换函数如下: #include <arpa/inet.h> uint32_t htonl(uint32_t hostlong); uint16_t htons(uint16_t hostshort); uint32_t ntohl... -
字节序转换函数与地址转换函数
2019-06-01 12:30:26字节序转换函数 需要包含头文件 #include <arpa/inet.h> 1.htons():把unsigned short类型从主机序转换到网络序(h:host,主机;n:net,网络;s:unsigned short,16位短整数) 2.htonl():把unsigned ... -
64位数字节序转换
2014-08-22 12:11:24项目中需要64位数的字节序转换,主机序转换成网路序或者相反转换,写了2个函数,有需要的可以参考。 -
网络通信之大小端模式及字节序转换函数解析
2020-11-23 17:27:25例如:2字节无符号短整型数字1可用2进制表示如下: 00000000 00000001 有些CPU按照以上顺序将数据存储到内存中,而有些数据则以倒序的顺序存储数据,如下所示: 00000001 00000000 如果在网络编程中,不考虑内存存储... -
64位网络字节序与主机字节序转换 ;32位网络字节序与主机字节序转换;16位网络字节序与主机字节序转换
2018-04-03 16:25:32主机字节序采用了:小端模式‘低对低,高对高’网络字节序采用了:大端模式‘低对高,高对低’16位/32位头文件netinet/in.h自带函数: 主机字节序转换网络字节序 uint16_t htons(uint16_t host16bit) uint32_t ... -
网络通信之大小端、字节序转换函数
2020-03-06 21:05:20在上篇文章中我们提到了UDP,TCP有关函数,并知道了一个重要的结构体struct sockaddr。想要实现通信首先要知道...struct sockaddr_in //此结构体大小是16字节 { sa_family_t sin_family; //2 字节 协议族(AF_INE... -
2、【网络编程】TCP报文段/网络字节序/主机字节序/网-主字节序转换函数
2018-11-08 15:58:50所以:在将一个地址绑定到socket的时候,请先将主机字节序转换成为网络字节序,而不要假定主机字节序跟网络字节序一样使用的是Big-Endian。 【示例】 #include < stdio . h > #include < arpa / inet . h > ... -
字节序转换函数
2019-09-05 17:21:18字节序转换函数 主机字节序数据转换成网络字节序数据 uint32_t htonl(uint32_t hostint32); 头文件: #include <arpa/inet.h> 功能:将32位主机字节序数据转换成网络字节序数据 参数: uint32_t : ... -
主机字节序与网络字节序转换
2018-11-08 15:25:54现代的电脑多采用小端字节序,而Java的虚拟机采用大端字节序,采用网络的也是大端字节序所以在网络传输中通常我们需要进行字节序的转换,否则接受网络数据的进程将不知道如何进行数据解析 Linux的系统环境下的Ç中... -
网络通信之字节序转换原理
2018-07-28 11:49:26相同字节序的平台在进行网络通信时可以不进行字节序转换,但是跨平台进行网络数据通信时必须进行字节序转换。 原因如下:网络协议规定接收到得第一个字节是高字节,存放到低地址,所以发送时会首先去低地址取... -
四个好用的网络字节序转换函数
2020-06-26 20:21:13作用:将本地端口字节序转换为网络字节序 ntohs() 函数原型: uint16_t ntohs(uint16_t netshort); 作用:将网络端口字节序转换为本地字节序 注意:使用上面函数需要包含头文件 #include <arpa/inet.h> IP... -
linux网络编程中的字节序转换
2017-09-20 23:45:26首先解释一下字节序的概念,所谓字节序是指多字节数据的存储顺序,比如0x1234要放在0000H和0001H两存储单元,有两种存储方式:大端格式为[0000H]=12,[0001H]=34和小端格式为[0000H]=34,[0001H]=12。 大端格式:将... -
计算机基础:字节序转换
2018-07-27 22:08:58字节序,顾名思义就是计算机存储基本数据类型时 字节的排列顺序,计算机存储字节的顺序分为两种:大端字节序和小端字节序,存储方式为 大端字节序的0x11在硬件地址的高位,而小端字节序的0x11在地址的低位。... -
64位网络字节序与主机字节序转换
2017-04-06 08:36:52unsigned long long ntohll(unsigned long long val) { if (__BYTE_ORDER == __LITTLE_ENDIAN) { return (((unsigned long long )htonl((int)((val > 32))) > 32)); } else i -
(1)IP地址、端口号 ——主机字节序与网络字节序转换 (2) inet_pton 函数与 htonl函数 的区别
2019-10-11 16:13:14IP地址的三种表示方式是点分十进制(字符串类型)、网络字节序、主机字节序。 域名如“ www.baidu.com”并不是IP地址的表示方式,“192.168.0.1”属于点分十进制(这个是字符串的形式)。 (1)点分十进制(字... -
大小端字节序介绍几转换
2017-12-18 14:21:08大小端字节序的介绍和相互转换。在c++中,有4个函数可以实现主机字节序到网络字节序的相互转换。 -
php字节序转换的方法
2021-03-26 15:36:11php字节序转换的方法:1、使用“htons”方法把unsigned short类型从主机序转换到网络序;2、使用“htonl”把“unsigned long”类型从主机序转换到网络序等。php主机字节序和网络字节序使用php编写socket程序时,也... -
字节序转换
2015-09-22 20:54:18字节序转换 即便有些事情你已经很熟悉了,但是有时候去做的时候还是会错误百出。今天有个同事问我写一个判断机器字节序的函数,如是信手写下来: int is_big_endian() { int test ...