linux: 讨论一下网络字节序--------大端与小端的差别

数据存储优先顺序的转换

计算机数据存储有两种字节优先顺序:高位字节优先(称为大端模式)和低位字节优先(称为小端模式)。内存的低地址存储数据的低字节,高地址存储数据的高字节的方式叫小端模式。内存的高地址存储数据的低字节,低地址存储数据高字节的方式称为大端模式。

eg:对于内存中存放的数0x12345678来说(注意,对于数据而言,此处12是高字节,78是低字节;对于地址而言,左边是低地址,右边是高地址)

如果是采用大端模式存放的,则其真实的数是:0x12345678

如果是采用小端模式存放的,则其真实的数是:0x78563412

综上:小端模式,先存低字节;大端模式先存高字节。

如果称某个系统所采用的字节序为主机字节序,则它可能是小端模式的,也可能是大端模式的。通常我们的电脑存放数据,都是以小端模式存放。而端口号和IP地址都是以网络字节序存储的,不是主机字节序,网络字节序都是大端模式。要把主机字节序和网络字节序相互对应起来,需要对这两个字节存储优先顺序进行相互转化。

Pra1

原题

实现将字符串形式存放的ip地址(点分十进制数)转换为主机字节序的32位二进制数值。IP为:“180.97.33.107”。十六进制为b4.61.21.6b

思路

一般我们的主机字节序均为小端字节序,也就是选存放数据的低字节。

1. 将字符串中的每个数取出来

2. 分别左移(注意,左移时一定会补0)

180 : 00 00 00 b4    左移0  位   00 00 00 b4
         97   : 00 00 00 61    左移8  位   00 00 61 00
         33   : 00 00 00 21    左移16位   00 21 00 00
         107 : 00 00 00 6b    左移24位   6b 00 00 00

3. 或操作

代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define IP "180.97.33.107"

/* 将ip地址转换为主机字节序的二进制数值,输出用16进制表示 */
static int my_atoh(char *ip)
{
    int arr[4]; /* 用于存放从ip地址中扣出的4个整数 */
    int my_ip;
    sscanf(IP,"%d.%d.%d.%d",arr,arr+1,arr+2,arr+3);
    my_ip = (arr[3] << 24) | (arr[2] << 16) | (arr[1] << 8) | arr[0];
    return my_ip;
}

int main(int argc, char *argv[])
{
    int my_host = my_atoh(IP);
    printf("ip  : %s \n",IP);
    printf("host: %x \n",my_host);
    return 0;
}

运行结果如下:

[[email protected] 0827]$ gcc -o main my_atoh.c -Wall
[[email protected] 0827]$ ./main
ip  : 180.97.33.107
host: 6b2161b4
[[email protected] 0827]$

注意

提一个与本题无关的注意点,当所有scanf函数,格式化读入时,如果遇到%s,会自己加‘\0’。

Pra2

原题

实现将主机字节序(小端模式存放)转换为网络字节序(大端模式存放)。即主机字节序为6b2161b4 –> b461216b

思路1

将6b与b4交换,21与61交换。

代码

#include <stdio.h>

int my_hton(int ip)
{
    /* &ip指向用32个bit表示的整型数ip,将int*类型的指针转换为char*类型的指针,
     * 则ptr指向用8个bit表示(第0-7位)的整型数,
     * ptr+1指向用8个bit表示(第8-15位)的整型数,
     * ptr+2指向用8个bit表示(第16-23位)的整型数,
     * ptr+3指向用8个bit表示(第24-31位)的整型数。*/
    
    char *ptr = (char*)&ip;

    char tmp;
    tmp = ptr[0];
    ptr[0] = ptr[3];
    ptr[3] = tmp;

    tmp = ptr[1];
    ptr[1] = ptr[2];
    ptr[2] = tmp;

    return ip;
}

int main(int argc, char *argv[])
{
    int my_host = 0x6b2161b4;
    int my_net = my_hton(my_host);
    printf("my_host: %x \n",my_host);
    printf("my_net : %x \n",my_net);
    return 0;
}

运行结果如下:

[[email protected] 0827]$ gcc -o main my_hton.c -Wall
[[email protected] 0827]$ ./main
my_host: 6b2161b4
my_net : b461216b

注意

实际上,ip地址为点分十进制,每个字节的表示范围都是0-255。而我们的char类型通常默认为有符号数,也就是说其表示范围是-128-127。那么我在代码中标记为黄色的部分是不是出错了呢?实际上并没有错,因为在此处我们只是关心ip每一位的存储情况,并不要求用到具体每个字节的实际十进制表示数值。在用printf格式化输出时,是根据数据在内存中的二进制形式来格式化的,而16进制形式是没有负数的。

思路2

1. 对于0x6b2161b4,先右移并进行与操作,取出各字节

例如:要取出6b,则0x6b2161b4右移24位,之后与0xff进行与操作即可

注意:千万不能先进行与操作,再右移。如,要取出6b,先使0x6b2161b4与0xff000000进行与操作,之后右移24位。这是错误的,因为右移会补符号位。(tips:左移补0,并舍弃符号位)

2. 分别再左移,调整到适当位置。 (以下两步类似于Pra1)

3. 或操作

代码

#include <stdio.h>

int my_hton2(int ip)
{
    int my_net;
    my_net = ((ip&0xff)<<24) | (((ip>>8)&0xff) << 16) | (((ip>>16)&0xff) << 8) | ((ip>>24)&0xff);
    return my_net;
}

int main(int argc, char *argv[])
{
    int my_host = 0x6b2161b4;
    int my_net = my_hton2(my_host);
    printf("my_host: %x \n", my_host);
    printf("my_net : %x \n", my_net);
    return 0;
}

Pra3

原题

实现将网络字节序转换为点分十进制

代码

#include <stdio.h>

static char* my_ntoa(int ip)
{
    static char buf[1024] = "";
    sprintf(buf,"%d.%d.%d.%d",(ip >> 24) & 0xff,(ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
    return buf;
}

int main(int argc,char *argv[])
{
    int my_net = 0xb461216b;
    printf("my_net: %x \n", my_net);
    printf("IP    : %s \n", my_ntoa(my_net));
    return 0;
}

时间: 2024-10-26 07:39:40

linux: 讨论一下网络字节序--------大端与小端的差别的相关文章

js arrayBuffer 字节序问题,小端法,大端法

原文博客 { var buffer = new ArrayBuffer(2) var bytes = new Uint16Array(buffer) bytes[0] = (65 << 8) + 66 var blob = new Blob([buffer], { type: 'text/plain' }) var dataUri = window.URL.createObjectURL(blob) open(dataUri) // BA 受系统的字节序影响,小端法 } { let buffe

主机序与网络字节序解析

网络数据流的地址:先发出的数据是低地址,后发出的是高地址 TCP/IP协议规定,网络数据流采用大端(big endian)字节序,低地址存高字节序,高地址低字节序(网络字节序) 主机字节序一般采用小端(little endian)存储,低地址存低字节序,高地址存高字节序 例子: int num=0x0102 01为高字节,02为低字节序小端存储 02 01大端存储 01 02 ntohs() 将一个无符号短整形数从网络字节顺序转换为主机字节顺序. printf("%ld\n",(eit

网络通信之 字节序转换原理与网络字节序、大端和小端模式

原文地址:http://www.cnblogs.com/fuchongjundream/p/3914770.html 一.在进行网络通信时是否需要进行字节序转换? 相同字节序的平台在进行网络通信时可以不进行字节序转换,但是跨平台进行网络数据通信时必须进行字节序转换. 原因如下:网络协议规定接收到得第一个字节是高字节,存放到低地址,所以发送时会首先去低地址取数据的高字节.小端模式的多字节数据在存放时,低地址存放的是低字节,而被发送方网络协议函数发送时会首先去低地址取数据(想要取高字节,真正取得是低

Linux 网络编程——网络字节序、地址转换

网络字节序 故事的起源 "endian"这个词出自<格列佛游记>.小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位. 我们一般将"endian"翻译成"字节序",将 Big-Endian 和 Little-Endian 称作"大端格式"和"小端格式". 字节序 字节序是指多字节

linux程序设计——主机字节序和网络字节序(第十五章)

15.2.10    主机字节序和网络字节序 当在基于intel处理器的linux机器上运行新版本的服务器和客户程序时,可以用netstat命令查看网络连接状况.它显示了客户/服务器连接正在等待关闭.连接将在一段超时间之后关闭,如下所示: 可以看到这条连接对应的服务器和客户的端口号.local address一栏显示的是服务器,而foreign address一栏显示的是远程客户(即使是在同一台机器上,它仍然是通过网络连接的).为了确保所有套接字都是不同的,这些客户端口一般都与服务器监听套接字不

大端法、小端法、网络字节序 转

一般来说,大部分用户的操作系统(如windows, FreeBsd,Linux)是Little Endian 的.少部分,如MAC OS ,是Big Endian 的. 所谓MSB (Most Significant Byte)就是,一个数字中,最重要的那位, 比如,12004,中文读作,一万两千零四,那最高位的1,就表示了一万,此处就称作MSB,最有意义的位. 而LSB (Least Significant Byte)与MSB相反,个位数4就可以称为LSB, 在草稿纸上演算的时候,我们习惯左边

大端与小端,大尾与小尾,高尾端与低尾端,主机字节序与网络字节序

概念剖析 一时记忆与理解大端.小端的概念很容易,但时间一长,对于相似的概念人类的记忆向来是模糊的,甚至是换位的.所以除非你的记忆非常牢靠,否则借助大端和小端这样的名字,你很难将概念与内容联系紧密. 也有文章提到用大尾与小尾的概念,个人觉得这个概念还是没有解决存储概念中的基本问题,大与小还是没有脱离以前的概念,但是引入了尾的概念,已经比大端与小端要更清晰一点. 目前对于记忆大小端,我觉得这篇文章中提到的高尾端/低尾端名词记忆方法比较科学.形象.实话说,当时计算机科学著作翻译Big Endian与S

大端法、小端法、网络字节序

关于字节序(大端法.小端法)的定义 <UNXI网络编程>定义:术语“小端”和“大端”表示多字节值的哪一端(小端或大端)存储在该值的起始地址.小端存在起始地址,即是小端字节序:大端存在起始地址,即是大端字节序.

网络通信时字节序转换原理与网络字节序、大端和小端模式

引言:在进行网络通信时是否需要进行字节序转换? 相同字节序的平台在进行网络通信时可以不进行字节序转换,但是跨平台进行网络数据通信时必须进行字节序转换. 原因如下:网络协议规定接收到得第一个字节是高字节,存放到低地址,所以发送时会首先去低地址取数据的高字节.小端模式的多字节数据在存放时,低地址存放的是低字节,而被发送方网络协议函数发送时会首先去低地址取数据(想要取高字节,真正取得是低字节),接收方网络协议函数接收时会将接收到的第一个字节存放到低地址(想要接收高字节,真正接收的是低字节),所以最后双