网络编程之字节序对跨平台数据传输的影响

转自 http://www.2cto.com/kf/201402/278681.html

关于字节序对跨平台数据传输的作用。我分下面几个方面整理了下,知识点应当算比较全了。
一。从服务端发送整数到客户端为例,看看字节序的应用。
二。什么是字节序?
三。什么是网络字节序

四。如何确定本机的大小端


一。从服务端发送整数到客户端为例,看看字节序的应用。 
服务端代码节选:

//发送整数
        //调用 send_num(sClient,num,sizeof(int));
        voidsend_num(intsockfd,int*data,intnbytes)
        {
            intsendData;
            //主机字节序转为网络字节序
            sendData = htons(*data);
            //发送给客户端
            //send(sockfd,sendData,nbytes,0);
            write(sockfd,sendData,nbytes);         
        }


客户端代码节选:

//接收整数
        voidrecv_num(intsockfd,int*data)
        {
            inttmpData;
             
            //发送给客户端
            //recv(sockfd,&tmpData,nbytes,0);
            read(sockfd,&tmpData,nbytes);  
 
            //网络字节序转为主机字节序
            data = htons(*tmpData);         
        }


上面代码可以放入我前面的socket例子中测试下。

注意,字符串型的无须转换,整型的则需要。 原因之一是网络传输是以字节为单位进行的。由sizeof(char)可知,一个字符对应一个字节,

无须转换, 但sizeof(int)会发现占四位,说明保存一个整型需要占4个字节。这时需要将其从本地字节序转为网络字节序才能正确的传输。


二。什么是字节序?

不同的计算机系统采用不同的字节序存储数据,同样一个4字节的32位整数,在内存中存储的方式就不同. 字节序分为小尾字节序(Little Endian)和大尾字节序(Big Endian), Intel处理器大多数使用小尾字节序, Motorola处理器大多数使用大尾(Big Endian)字节序;
小尾就是低位字节排放在内存的低端,高位字节排放在内存的高端。
大尾就是高位字节排放在内存的低端,低位字节排放在内存的高端。

可以用printf("%02x,%02x,%02x,%02x",p,p+1,p+2,p+3);类似的方式打印出来做对比。


三。什么是网络字节序
TCP/IP各层协议将字节序定义为大尾,因此TCP/IP协议中使用的字节序通常称之为网络字节序。
这意味着,在数据流传输过程中,本地数据流需转为网络字节序传输, 然后网络数据流再转换成本地字节序数据流。
所以c语言提供了一堆转换函数:
htons() : 将16位无符号整数从本地字节序转换成网络字节序
htonl() : 将32位无符号整数从本地字节序转换成网络字节序
ntohs() : 将16位无符号整数从网络字节序转换成本地字节序
ntohl() : 将32位无符号整数从网络字节序转换成本地字节序

不过没有针对64位整型的转换函数,而这个还是常用到的。
转一个64位字节序转换函数(http://www.cppblog.com/aa19870406/archive/2012/06/20/179517.html 找的):

unsignedlonglong ntohll(unsigned longlong val)
 {
    if(__BYTE_ORDER == __LITTLE_ENDIAN)
     {
        return(((unsigned longlong )htonl((int)((val << 32) >> 32))) << 32) | (unsigned int)htonl((int)(val >> 32));
    }
    elseif (__BYTE_ORDER == __BIG_ENDIAN)
     {
        returnval;
    }
}
 
unsignedlonglong htonll(unsigned longlong val)
 {
    if(__BYTE_ORDER == __LITTLE_ENDIAN)
     {
        return(((unsigned longlong )htonl((int)((val << 32) >> 32))) << 32) | (unsigned int)htonl((int)(val >> 32));
    }
    elseif (__BYTE_ORDER == __BIG_ENDIAN)
     {
        returnval;  www.2cto.com
    }
} 


四。如何确定本机的大小端
这个网上一大堆,下面找的两种方法展示得很清楚:
第一种方法:

思路:利用指针的强制类型转换

#include <stdio.h> 
intmain(void)
{   
    intdata1 = 0x12345678;  
    inti;   
    for(i=0; i<4; i++)  
    {      
        printf("%#x ----->%p\n",*((char*)&data1 + i),(char*)&data1 + i);   
    }    
    return0;
}

第二种方法

思路:利用共用体所有数据都从同一地址开始存储这个特性来区分。

#include <stdio.h>
intmain(void)
{
    inti;
    union endian
    {
        intdata;
        charch;
    }test;
    test.data = 0x12345678;
    if(test.ch == 0x78)
    {
        printf("little endian!\n");
    }
    else
    {
        printf("big endian!\n");
    }
  
    for(i=0; i<4; i++)
    {
        printf("%#x ------- %p\n",*((char*)&test.data + i),(char*)&test.data + i);
    }
    return0;
}


运行上面任意一种方法,都能很清楚的展示出字节的顺序来出。

总之,字节序,大小端转换在网络通讯中非常重要,特别是跨平台时要特别注意。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值