二进制数据与大小端不得不说的秘密

    在学习unix网络编程的时候,遇到一个问题,那就是二进制数据在网络中传输中会受到大小端、机器位数等影响。那么如何影响呢?我手头有两台设备64位的ubuntu(小端)和32位linux开发板(MIPS架构、大端),说做就做。

    我在32位机器(大端)上搭建服务端、在64位机器(小端)上搭建客户端。程序设计为客户端向服务端发送两个long类型的数据,服务端接收后将两个数据相加并返回给客户端。

服务端端核心代码如下:

    for ( ; ; ) 
    {   
        if ( (n = read(sockfd, &args, sizeof(args))) == 0)
            return;
        result.sum = args.arg1 + args.arg2;
        printf("%ld-%ld\n", args.arg1, args.arg2);                                                                                                            
        write(sockfd, &result, sizeof(result));
    }   
客户端核心代码如下:



    while (fgets(sendline, MAXLINE, fp) != NULL)                                                                                                              
    {
        if (sscanf(sendline, "%ld%ld", &args.arg1, &args.arg2) != 2)
        {
            printf("invalid input: %s\n", sendline);
            continue;
        }
        write(sockfd, &args, sizeof(args));
        if (read(sockfd, &result, sizeof(result)) == 0)
        {
            printf("\033[32mread failed!\033[0m");
        }
        printf("%ld\n", result.sum);
    }

测试数据为1 2

出乎意料的事情发生了,在得到两个意想不到的数后得到8589934593常数。

我把这个常数转换为16进制再去观察0x200000001,感觉到问题的关键了

64位系统小端发送1经过网络字节转换为01 00 00 00 00 00 00 00在32位机器上得到的arg1却是0x01 00 00 00,arg2为0x02 00 00 00,相加之和为0x01 00 00 00,然后发送给服务端,然后2继续转换:arg为0x02 00 00 00 ,arg2为0x 00 00 00相加后为0x02 00 00 00.客户端接收long类型是8个字节,等待服务端发生数据,然后只接收到4个字节的数据,这时会得到一个随机数,这里是140638704107521。这是第一次数据传输后的影响。

第二次,前面不变,客户端继续接收long,这时,在sock缓冲区,上一次剩余的结果(02 00 00 00)将被返回,所以这次也是一个随机数。这里是

140638704107522。

第三次,前面不变,客户端继续接收long,这时候,在sock缓冲区是这样的数据(01 00 00 00 02 00 00 00这时,小端接收会是20 00 00 00 1(第一个为符号位),原来是这样。

为什么第一次和第二次是随机数?原来这是在申请空间时没有初始化,将result结构体bzero就可以观察到,第一次接收1,第二次接收2.

源代码链接在这endian_test

你可能感兴趣的:(unix网络编程)