本地字节序和网络字节序
字节序指不同的CPU访问内存中多字节数据的时候,存在大小端的问题,并且一定是访问多字节数据的时候才会存在大小端的问题,如果CPU访问的是字符串,则不存在大小端的问题;
那么如何判断发送端和接收端是大端模式还是小端模式呢,首先:
●小端序(little-endian) - 低序字节存储在低地址;将低字节存储在起始地址,称为“Little-Endian”字节序,Intel、AMD等采用的是这种方式;
●大端序(big-endian)- 高序字节存储在低地址;将高字节存储在起始地址,称为“Big-Endian”字节序,由ARM、Motorola

例如有一个int型的变量:int i = 0x12345678;这里的“12”就是变量的高端,“78”就是变量的低端;

其实本地和网络字节序的转换,主要是为了不同平台之间兼容性的问题,例如两台主机要进行网络数据的传输,有两种情况(首先我们要知道,网络中传输的数据必须按网络字节序,即大端字节序;因为网络传输过程中的中间设备的处理器都是大端模式的,这是规定好的):
1.发送端是大端模式,接收端是小端模式;如果发送端不进行字节序的转换,那么这个应用程序运行到发送端是小端模式的主机上之后,网络传输就会有问题,比如说网络传输过程中的中间设备不能正确的读取收发端的IP地址和MAC地址;
2. 发送端是小端模式,接收端是大端模式;如果接收端不进行字节序的转换,而且发送端还传输了多字节的数据的话,那么这个应用程序运行到接收端是小端模式的主机上之后,接收端接收到的数据就会有问题;

因为两台设备进行网络传输,这两台设备可能不是一个平台上的CPU,不同平台上的两个CPU,它们可能两个都是大端模式的,也有可能都是小端模式的,还有可能一个是大端模式一个是小端模式或者一个是小端模式一个是大端模式,所以两台机器要进行网络传输,必须统一发送、传输和接受的模式,由此课件数据转换的主要目的就是为了保证兼容行;

当然,字节序转换函数里面已经包含了这种方法,函数本身会直接的判断当前操作系统中的CPU的大端模式还是小端模式,需要转换的话就转换,不需要转换的时候就原样输出;

下面是本地字节序到网络字节序转换的函数:
主机字节序到网络字节序
#includ <arap/inet.h>
u_long htonl (u_long hostlong); /这里的"h"指的是:host,"n"指的是network,"l"指的是long型/
u_short htons (u_short short); /这里的"h"和"n"和上面是一样的,这里的"s"指的是short型/
网络字节序到主机字节序
u_long ntohl (u_long hostlong);
u_short ntohs (u_short short);
htonl\htons和ntohl\ntohs这两种类型的函数都是将多字节的数据进行颠倒操作,下面是测试:
int i = 0x00414243;
int j,k,l;

j = htonl(i);
k = htonl(j);
l = ntohl(j);printf("i:%s\n",(char *) &i);
printf("j:%s\n",(char *) &j);printf("k:%s\n",(char *) &k);
printf("l:%s\n",(char *) &l);

输出结果是:
linux@ubuntu:~/Embedded_learning/LV6/day2$ ./a.out
i:CBA
j: /这里输出了空,原因是htonl()函数将0x00414243颠倒为0x43424100,因为是小端模式,打印的时候第一k:CBA 个读到的数字是零,而零在ASCII中表示的是’\0’,’\0’代表的是字符串的结束符,所以就输出了空;/
l:CBA
linux@ubuntu:~/Embedded_learning/LV6/day2$

从这个测试看到好像htonl()和ntohl()函数的功能没有上面区别,但是我认为是有区别的:
1.htonl()函数因为是本地字节序到网络字节序,里面应该实现了判断当前使用函数的机器是否为大端模式,如果为大端模式的话就放弃转换,直接返回要转换的多字节数据,否则就将本地字节序转换为网络字节序;
2.ntohl()函数是网络字节序到本地字节序,里面应实现了判断当前使用函数的机器是否为大端模式,如果为大端模式的话就放弃转换,并直接返回要转换的多字节数据,否则就将网络字节序转换为本地字节序;
好像又是一样的啊;求解释这两个函数内部实现的区别;

IP地址的转换函数
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

in_addr_t inet_addr(const char cp); /cp是点分形式的IP地址,返回值是由点分形式的IP地址转换过来的32位的
IP地址,这里要注意的是,这里面已经包含了本地字节序的转换了,而且这个
函数内部还会自动的判断,如果本地字节序是大端模式的话就直接返回,不进
行转换;如果是小端模式的话才会进行转换,并返回转换后的32位数值;所
以,不用特意的去调用htonl()等函数;/
inet_addr()函数将Internet主机地址cp从IPv4数字和点符号转换成网络字节顺序的二进制数据。如果输入无效,则返回INADDR_NONE(通常是-1)。使用这个函数是有问题的,因为-1是一个有效地址(255.255.255.255)。避免使用它来支持inet_aton()、inet_pton(3)或getaddrinfo(3),它们提供了一种更简洁的方式来指示错误返回。
使用这个函数时有两点需要注意:
1.inet_addr()这个函数只适用于IPV4;
2.inet_addr()这个函数出错时返回-1;但是由于-1在32位的计算机中的补码形式也是四个255(-1在32位系统中的补码为:ffff ffff)所以在使用的时候要特别的注意不能使用255.255.255.255这个IP地址;具体见下面的测试:
if(argc != 2){
perror(“Missing argc”);
exit(-1);
}
unsigned int i;
i = inet_addr((argv+1));
if(i == -1){
perror(“inet_addr failed”);
exit(-1);
}
printf("%s\n",*(argv+1));
printf("%u\n",i);
执行结果:
linux@ubuntu:~/Embedded_learning/LV6/day2$ ./a.out 255.255.255.255
inet_addr failed: Success /可以看出,这样的执行结果会出现误判的情况/
linux@ubuntu:~/Embedded_learning/LV6/day2$
不适用255.255.255.255地址就是正确的:
linux@ubuntu:~/Embedded_learning/LV6/day2$ ./a.out 255.255.255.254
255.255.255.254
4278190079
linux@ubuntu:~/Embedded_learning/LV6/day2$
由于inet_addr()函数的弊端,所以就引进了下面的两个函数:inet_pton()和inet_ntop()

#include <arpa/inet.h>
int inet_pton(in af,const char *src,void *dst); /convert IPv4 and IPv6 addresses from text to binary form/
inet_pton()这个函数相比inet_addr()函数的优点有:
1.它能转换IPv4和IPv6两种文本地址到二进制;
2.能正确的处理255.255.255.255的转换问题;

如果成功,inet_pton()将返回1(网络地址已成功转换)。如果src不包含表示指定地址族中的有效网络地址的字符串,则返回0。如果af不包含有效的地址家族,则返回-1并将errno设置为EAFNOSUPPORT。

参数:
af :af参数必须是AF_INET或AF_INET6;
AF_INET : src指向一个字符串,该字符串包含一个点十进制格式的IPv4网络地址,“ddd.ddd.ddd”。ddd”,其中ddd是一个范围为0到255的三位数的小数。地址被转换为struct in_addr并复制到dst,它必须是sizeof(struct in_addr)(4)字节(32位)长。
/*Internet address. */
typedef uint32_t in_addr_t;
struct in_addr{
In_addr_t s_addr;
};

AF_INET6 : src指向一个包含IPv6网络地址的字符串。地址被转换为struct in6_addr并复制到dst,它必须是sizeof(struct in6_addr)(16)字节(128位)长。IPv6地址的允许格式遵循以下规则:

  1. 首选的格式是x : x : x : x : x : x : x : x。这种形式由8个十六进制数组成,每个十六进制数表示一个16位的值(即,每个x最多可以是4个十六进制数字)。
  2. 可以将一组首选格式的连续零值缩写为::。一个地址中只能出现一个::的实例。例如,环回地址0:0:0:0:0:0:1可以缩写为::1。通配符地址由所有0组成,可以写成::。
  3. 为了实现IPv4-IPv6互通,IPv4地址会嵌入IPv6地址中,此时地址常表示为:X:X:X:X:X:X:d.d.d.d,
    也就是前6组用冒分十六进制表示,后二组用十进制表示,而最后32bit地址则使用IPv4的点分十进制表示,例如::192.168.0.1与就是一个典型的例子 。
  4. 如何将ipv4转换为ipv6地址? 上面我们提到了,ipv4地址要与ipv6地址互通,需要将ipv4转换为ipv6地址。
    举例:如果IPv4的一个地址为135.75.43.52,现有32位地址,那么如何转换为ipv6呢?
    ① 非标准转换:只需要在ip地址前面6组共96位补充0即可,即0000:0000:0000:0000:0000:0000:135.75.43.52也就是::135.75.43.52(内嵌IPv4表示法)
    ② 标准转换:135.75.43.52 按十六进制算出即87.4B.2B.34,而87.4B.2B.34串地址一组还是8位,所以需要两组v4地址合成v6地址,再把前96位补零,它可以被转化为0000:0000:0000:0000:0000:0000:874B:2B34或者::874B:2B34。

/* IPv6 address */
struct in6_addr
{
union
{
uint8_t __u6_addr8[16];
#if defined __USE_MISC || defined __USE_GNU
uint16_t __u6_addr16[8];
uint32_t __u6_addr32[4];
#endif
} __in6_u;
#define s6_addr __in6_u.__u6_addr8
#if defined __USE_MISC || defined __USE_GNU
#define s6_addr16 __in6_u.__u6_addr16
#define s6_addr32 __in6_u.__u6_addr32
#endif
};

const char *inet_ntop(int af,const void src,char dst,socklen_t size); / convert IPv4 and IPv6 addresses from binary to
text form
/
此函数将af地址家族中的网络地址结构src转换为字符串。结果字符串被复制到dst指向的缓冲区中,该缓冲区必须是非空指针。调用者在参数大小中指定此缓冲区中可用的字节数。

inet_ntop()扩展了inet_ntoa(3)函数以支持多个地址族,而inet_ntoa支支持IPv4地址;

AF_INET: src指向一个struct in_addr(按网络字节顺序),它被转换成点状小数格式的IPv4网络地址“ddd.ddd.ddd.ddd”。缓冲区dst必须至少有INET_ADDRSTRLEN字节长(#define INET_ADDRSTRLEN 16)。
AF_INET6: src指向一个struct in6_addr(按网络字节顺序),它被转换成这个地址最合适的IPv6网络地址格式的表示。缓冲区dst必须至少有INET6_ADDRSTRLEN字节长(#define INET6_ADDRSTRLEN 46)。

int inet_aton(const char * cp,struct in_addr * inp); /老师说先不管这个函数/
char *inet_ntoa(struct in_addr in); /老师说先不管这个函数/
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
可能是因为这两个函数只支持IPv4的格式;

本地字节序和网络字节序相关推荐

  1. 本地字节序与网络字节序的相互转换(IP地址、端口号)

    一般数据在内存中是按照字节存储的,存储的方式分为大端和小端.在不知道对方主机的存储方式的情况下,我们不知道是否需要转换数据的存储方式.因此,TCP/IP协议规定:发送到网络的数据流应采用大端字节序! ...

  2. 本地字节序和网络字节序的转换

    1.背景 "端口号"或者"点分十进制的IP"必须先转化为"网络字节序",才能在网络环境中传输. TCP/IP 规定,网络数据流采用大端字节序 ...

  3. 主机字节序与网络字节序的转换函数:htonl、ntohl、htons、ntohs【转】

    (转自:https://blog.csdn.net/kulala082/article/details/53431473) Part 1: htons函数具体解释 在Linux和Windows网络编程 ...

  4. linux网络编程一:主机字节序与网络字节序的的判断

     linux网络编程一:主机字节序与网络字节序的的判断(1)现代CPU的累加器一次能装载至少4字节(32位),即一个整数.那么这4字节在内存中排列的顺序将影响它被累加器装载成的整数值,这就是字节序问题 ...

  5. Linux---主机字节序与网络字节序

    现在的CPU累加器一次能够装载至少4个字节的一个整数,那么字节在内存中的排列顺序不同,导致累加器使用的结果不同,这就是字节序问题 . 例如: 我们存储一个int类型的数字:int a = 1; 主机字 ...

  6. 什么是字节序(端序、低端字节序、高端字节序、网络字节序)

    前言 一个内容为12(字符串)的文本文件,它的第一个字节是什么(小端序)?如果你的回答是0x32,那你真的应该好好理解下字节序了.如下图所示,我这里的正确答案是0x31.当然如果你的回答是不一定,这似 ...

  7. 主机字节序与网络字节序的转换函数:htonl、ntohl、htons、ntohs

    Part 1: htons函数具体解释      在Linux和Windows网络编程时需要用到htons和htonl函数,用来将主机字节顺序转换为网络字节顺序. 在Intel机器下,执行以下程序 i ...

  8. 【Linux】主机字节序和网络字节序

    (一)问题提出:为什么要有主机字节序和网络字节序的存在? 现在大多数PC机器都是小端字节序(小端存储),也称为主机字节序:但不排除有大端PC机器的存在. 若在两台字节序不同的主机上传输数据时,接收端将 ...

  9. 字节序 主机字节序与网络字节序互相转换

    目录 1.什么是字节序? 2.字节序分类 3.为什么要有大端字节序和小端字节序? 4.主机字节序和网络字节序 5.主机字节序与网络字节序的转换 6.怎么判断自己的主机是小端字节序还是大端字节序呢? 7 ...

最新文章

  1. RIFF格式声音文件的实现(转)
  2. 构造代码块会想你所想
  3. javascript运动系列第七篇——鼠标跟随运动
  4. 冲突域、广播域的通俗讲解
  5. Ocelot(三)- 服务发现
  6. 判断只有符号数字 java_java编程 判断输入的字符,数字,及其他符号的个数
  7. 2.9.JavaScript--内置对象
  8. java jtextfield 输入_【java】JTextField与JComboBox结合动态匹配输入信息
  9. 25. 熟悉非标准的哈希容器
  10. 监控mysql连接池信息_druid-带监控功能的数据库连接池
  11. 基于SSM实现在线考试及题库管理系统
  12. 内网穿透工具的原理与开发实战
  13. 中国信息安全技术标准体系框架
  14. vivado修改下载器下载速率
  15. 腾讯笔试题——逆序对
  16. 学习windows编程 day3 之 自定义画笔的两种方法
  17. 解决 Exception: ROM is missing for pong, see https://github.com/openai/atari-py#roms for instructions
  18. oracle和mysql的mod函数
  19. 利用redis,模拟控制库存消耗场景
  20. 换个花样玩C++(1)步步深入窥探const

热门文章

  1. H3C交换机 路由器 Save 命令详细分析
  2. Mac安装微信支付安全控件问题
  3. android 选择银行类型,vue2.0实现银行卡类型种类的选择
  4. 20131007-STM8L101F3P6关于硬件IIC写时序和勘误部分的翻译
  5. Reflex WMS入门系列之二十一:关闭一个不需要的盘点
  6. Python量化交易学习笔记(25)——Data Feeds扩展
  7. 学校计算机室班班通的使用巡检维护记录表,学校班班通、设备使用记录簿表.doc...
  8. 机器人曲轴上下料_曲轴生产线自动上下料机器人的解决方案
  9. cf----2019-10-03(Minimum Value Rectangle,Plasticine zebra,Weakened Common Divisor)
  10. vivado 配置matlab,Matlab vivado