linux 大端 Linux怎么学
识别Linux大小端识别深入浅出linux大小端
Linux大小端识别是对于存储器编码方式的识别,它是指在存储器中字节的顺序,大端表示存储器中字节的高位放在低位地址,而小端则恰好相反,高位存储在高地址。在开发中会遇到不同的系统、处理器,存储器编码方式也是不尽相同,例如x86编译出来的可执行文件是字节顺序都是小端的。而在ARM之类的开发中,编译出的文件的字节顺序可以根据不同的处理器设置大端或小端,开发者需要针对不同的处理器进行字节顺序的检测,并且采用不同的程序进行处理。
一种最简单的Linux大小端识别方法就是使用CPUID命令检测CPU的类型,在不同的架构中采用不同的汇编指令,实现Linux大小端识别,代码如下:
//Check CPU Type
asm volatile(“movl$0x01,%%eax;\
xorl%%edx,%%edx;\
cpuid;\
movl%%edx,%0″
:”=r”(info->EDX)::”%eax”,”%edx”);
// Checks if the CPU is big or little endian
if((info->EDX)& 0x00000001){
info->ENDIANNESS= LITTLE_ENDIAN;
}
else{
info->ENDIANNESS= BIG_ENDIAN;
}
上面的代码使用汇编指令CPUID,然后将edx寄存器中第一位的值判断出CPU类型,从而识别Linux大小端。如果根据edx的第一位的值的话,对于x86系统下查询出来的结果是0,则为小端模式,如果查询结果是1,则为大端模式。
此外,如果要实时的进行大小端的转换,同样可以使用汇编指令来进行,具体代码如下:
//Swap endianness
asm volatile(“rorl$16,%0”
:“=q”(info->data)
::“cc”);
上面的代码使用汇编指令rorl对变量info->data进行移位16次,实现大小端的转换,将原来的小端字节序转换成大端字节序或者将大端字节序转换成小端字节序。
总之,Linux大小端识别的实现较为简单,不仅可以使用cpuid命令,还可以使用rorl汇编指令来识别CPU类型,以及实时的进行大小端转换,这样可以使得我们可以在不同系统之间正常实现数据同步。
linux网络编程系列(二)-1socket套接字基本概念详解
套接字,也叫socket,是操作系统内核中的一个数据结构,它是网络中的节点进行相互通信的门户。网络通信,说白了就是进程间的通信(同一台机器上不同进程或者不同计算机上的进程间通信)。在网络中,每一台计算机或者路由都有一个网络地址,就是IP地址。两个进程通信时,首先要确定各自所在的网络节点的网络地址。但是,网络地址只能确定进程所在的计算机,而一台计算机上一般都是同时运行着多个进程,所以仅凭网络地址还不能确定到底是和网络中的哪一个进程进行通信,因此套接口中还需要包括其他的信息,比如端口号和协议。
端口号的范围从0-65535,分类如下:一类是众所周知的,公用的端口号,其值一般为0~1024,例如http的端口号是80,ftp为21,ssh为22,telnet为23等;一类是用户自己定义的,通常是大于1024并且小于65535的整型值。
通常我们在表达IP地址时习惯使用点分十进制表示的数值(或者是为冒号分开的十六进制Ipv6地址),而在socket编程中使用的则是二进制值,这就需要对这两个数值进行转换。
ipv4地址:32bit, 4字节,相当于一个整型,通常采用点分十进制记法,例如对于:10000000 00001011 00000111 00011111,点分十进制表示为:128.11.7.31。
socket是一种特殊的I/O接口,它也是一种文件描述符。如第一节所说,通过它不仅能实现本地机器上的进程之间的通信,而且通过网络能够在不同机器上的进程之间进行通信。socket也有一个类似于打开文件的函数调用,该函数返回一个整型的socket描述符,随后的连接建立、数据传输等操作都是通过这个socket描述符来实现的。
用于TCP通信,流式套接字提供可靠的、面向连接的通信流,使用TCP协议,从而保证了数据传输的正确性和顺序性。用于UDP通信,数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且是不可靠的,它使用数据报协议UDP。原始套接字允许对底层协议如IP或ICMP进行直接访问,它功能强大但使用较为不便,主要用于一些自定义协议的开发。
计算机数据存储有两种字节优先顺序:高位字节优先(称为大端模式)和低位字节优先(称为小端模式)。对于内存中存放的数0x12345678来说:如果是采用大端模式存放的,则其真实的数是:0x12345678;如果是采用小端模式存放的,则其真实的数是:0x78563412;端口号和IP地址都是以网络字节序存储的,不是主机字节序,网络字节序都是大端模式,而主机字节序则一般都是小端模式(也有特殊的是大端模式,这里不考虑)。所以在网络连接过程中,要把主机字节序和网络字节序相互对应起来,需要对这两个字节存储顺序进行转换。
端口号和IP地址都是以网络字节序存储的,不是主机字节序,网络字节序都是大端模式,而主机字节序则一般都是小端模式(也有特殊的是大端模式,这里不考虑)。所以在网络连接过程中,要把主机字节序和网络字节序相互对应起来,需要对这两个字节存储顺序进行转换。这里用到四个函数:htons(),ntohs(),htonl()和ntohl().这四个函数分别实现网络字节序和主机字节序的转化,这里的h代表host,n代表network,s代表short,l代表long。通常16位的IP端口号用s代表,而IP地址用l来代表。
在表达地址时采用的是点分十进制表示的数值(或者是为冒号分开的十进制Ipv6地址),而在socket编程中使用的则是32位的网络字节序的二进制值,这就需要对这两个数值进行转换。这里在Ipv4中用到的函数有inet_aton()、inet_addr()和inet_ntoa(),而IPV4和Ipv6兼容的函数有inet_pton()和inet_ntop()。
函数inet_aton():将点分十进制数的IP地址转换成为网络字节序的32位二进制数值。返回值:成功,则返回1,不成功返回0.参数straddr:存放输入的点分十进制数IP地址字符串。参数addrptr:传出参数,保存网络字节序的32位二进制数值。函数inet_ntoa():将网络字节序的32位二进制数值转换为点分十进制的IP地址。函数inet_addr():功能与inet_aton相同,但是结果传递的方式不同。inet_addr()若成功则返回32位二进制的网络字节序地址。
函数inet_pton跟inet_aton实现的功能类似,只是多了family参数,该参数指定为AF_INET,表示是IPv4协议,如果是AF_INET6,表示IPv6协议。函数inet_ntop跟inet_ntoa类似,其中len表示表示转换之后的长度(字符串的长度)。
一般来讲,我们在上网的过程中都不愿意记忆冗长的IP地址,尤其到Ipv6时,地址长度多达128位,那时就更加不可能一次性记忆那么长的IP地址了。我们一般记住的,都是这个网站的域名地址。大家可以利用ping baidu.com来得到百度公司的ip地址。系统是如何将 baidu.com这个域名转化为IP地址的呢?在linux中,最常用的是gethostbyname()和gethostbyaddr(),它们都可以实现IPv4/IPv6的地址和主机名之间的转化。其中gethostbyname()是将主机名转化为IP地址,gethostbyaddr()则是逆操作,是将IP地址转化为主机名。
函数原型:
Example:
编译运行g++ test.cpp./a.out baidu.com
如何确认系统是采用大端还是小端**
如何确认系统是采用大端还是小端**
1、大小端
**大端(存储)模式:**是指一个数据的低位字节序的内容放在高地址处,高位字节序存的内容放在低地址处。
如:一个数0x12345678存放在一个4字节空间里
**小端(存储)模式:**是指一个数据的低位字节序内容存放在低地址处,高位字节序的内容存放在高地址处。(可以总结为“小小小”即低位、低地址、小端)
如:一个数0x12345678存放在一个4字节空间里
在计算机系统中,我们是以字节为单位存放数据的,每个地址单元都对应着一个字节,一个字节为8bit。但在C语言中存在不同的数据类型,占用的字节数也各不相同,那么就存在怎样存放多个字节的问题,因此就出现了大端存储模式和小端存储模式。
大小端是由CPU和操作系统来决定的,在操作系统中,x86和一般的OS(如windows,FreeBSD,Linux)使用的是小端模式,但比如Mac OS是大端模式。
知道为什么有模式的存在,下面需要了解下具有有什么应用场景:
1)不同端模式的处理器进行数据传递时必须要考虑端模式的不同
2)在网络上传输数据时,由于数据传输的两端对应不同的硬件平台,采用的存储字节顺序可能不一致。所以在TCP/IP协议规定了在网络上必须采用网络字节顺序,也就是大端模式。对于char型数据只占一个字节,无所谓大端和小端。而对于非char类型数据,必须在数据发送到网络上之前将其转换成大端模式。接收网络数据时按符合接受主机的环境接收。
2、如果知道当前系统是采用的什么模式:
1)
通过查看一个变量在内存中存放的位置来判断
int test1_endian(){
int i= 1;
char*a=(char*)&i;
if(*a== 1)
printf("小端\n");
else
printf("大端\n");
return 0;
}
2、用联合体
int test2_endian(){
union{
int i;
char c;
}un;
un.i= 1;
if(un.c== 1){
printf("小端");
}
else{
printf("大端");
}
return 0;
}