字节序
网络字节序
网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操做系统等无关,从而能够保证数据在不一样主机之间传输时可以被正确解释。网络字节顺序采用big endian排序方式。
主机字节序
整数在内存中保存的顺序,不一样的处理器对应不容的模式,在通常的网络编程过程中,对于字节序的问题咱们不用关心,除非涉及到跨平台的通讯和资源共享。编程
Little endian :将低序字节存储在低地址
好比一个int类型的值 0x12345678数组
Big endian :将高位字节存储在低地址网络
在我开始学习socket网络编程的时候,对与字节序的转化,最直观的就是对于端口号的转换 htons(),其实ip也是作了转换的,inet_addr(const char *strptr) 就是将字符串转换为32位二进制网络字节序的IPV4地址,而在数据传输send和read的时候几乎没有用过字节序的转换,难道是在传输的时候底层作了什么特殊处理,不用作字节序转换?
其实并无,在个人写的数据传输代码当中,几乎所有使用的是以C风格字符串的形式去传输的数据,考虑到一个C风格字符串的实质是一个包含着许多char的数组,每个char在现代计算机中几乎都是表示计算机中的一个字节。所以,当读写C风格字符串时,其最小的元素单位是一个字节;并且数组在内存单元中地址的排列顺序是递增的,例如定义char str[5];这么一条语句,假设&str[0]的地址为1000,则&str[1]的地址为1001,依次类推。因此不论从直观含义或者底层技术来看,字符串的存储都是相对字节序独立的,因此在作C风格字符串的传输时候,不须要考虑字节序的问题,直接读取拿去用就行了。
可是当你传输的数据是一个类型大于一个字节的类型的数据的时候,因为,不一样硬件的体系结构接受不一样字节序的数据表示,所以当同一段内存数据在不一样的机器中进行读取和写入的时候,其所支持的字节序就显得尤其关键。设想在x86计算机中将(123888)10写入二进制文件中,因为x86支持Little-Endian,因此该数在文件中保存为(00003F1E)16。当在PowerPC计算机中读取该整数时,因为它支持的是Big-Endian,故读取的结果将是(16158)10,截然不同。因此在传输其余非字符串类型的时候,须要对传输过来的数据进行字节序转换。
能够用如下这段代码来判断机器的字节序
{
int i = 1;
if (*(char*)&i == 0)
// Big Endian
else
// Little Endian
}架构
字节序不是由操做系统决定的,而是由cpu架构决定的
CPU架构是CPU厂商给属于同一系列的CPU产品定的一个规范,主要目的是为了区分不一样类型CPU的重要标示。目前市面上的CPU指令集分类主要分有两大阵营,一个是intel、AMD为首的复杂指令集CPU,另外一个是以IBM、ARM为首的精简指令集CPU。两个不一样品牌的CPU,其产品的架构也不相同,例如,Intel、AMD的CPU是X86架构的,而IBM公司的CPU是PowerPC架构,ARM公司是ARM架构。socket
假设咱们有这么一段代码
强制类型转换
{
unsigned char endian[2] = {1, 0};
short x;学习
x = *(short *) endian;
}
那么最后获得x的结果是多少呢?是否是简单的就是endian数组的第一个元素1呢?答案是错,x的数值须要根据运行时的环境来决定。让咱们回忆一下C语言的指针指向多大的内存以及怎么去解释所指的这块内存是由指针所指向的类型来肯定的,在上述代码中,将endian数组的首元素指针强制转换成short *的指针,那么编译器在解释它的时候将再也不把它指向的内存空间视为1 byte,而是short的长度——2 byte;更重要的是当咱们对这个指针解引用的时候将会获得的值会是什么。再回到上面所提到的字符串或者字符数组在计算机中就是依照数组顺序存放的,那么这个时候endian数组占用了两个字节,其内存数据为:0100。当该指针强制转换为指向short的指针并解引用时,计算机将一次读取两个字节,这个时候字节序就发挥它的影响了。在支持Little-Endian的机器中x的值将是1(读取为0001),而在支持Big-Endian的机器中x的值就是256(读取为0100)。所以在对指针进行类型转换并解引用,特别是在单字节到多字节数据的转换时,要特别注意字节序是否会使得预期结果出现误差。上面那段判断字节序的代码就是根据这个思路来的。操作系统