手动IP怎么转换成网络字节序

手动IP怎么转换成网络字节序,第1张

我刚刚也遇到这个问题

在报文中ipv4一般由32位来表示,就是无符号的int型,ip地址转换成网络字节序就是int转成网络字节序

即低位在前高位在后

举个列子吧

IP地址为 19216801的话首先转换32位二进制的数字(点去掉) ,每8位就可以表示0---255,所以ipv4地址就由32位来表示,这样的话就变成了(192)ab(168)cd(0)ef(1)gh这几个组成的一个32位数字(二进制就不弄了,一个字母代表4位),变成网络字节序就是反过来hgfedcba

第一次回答问题,给分吧

一、定义:

大端模式(Big Endian):数据的高字节,保存在内存的低地址中;数据的低字节,保存在内存的高地址中。

小端模式(Little Endian):数据的高字节,保存在内存的高地址中;数据的低字节,保存在内存的低地址中。

例如:数字0x12 34 56 78在内存中的表示形式为:

1)大端模式:

低地址 -----------------> 高地址

0x12  |  0x34  |  0x56  |  0x78

2)小端模式:

低地址 ------------------> 高地址

0x78  |  0x56  |  0x34  |  0x12

可见,大端模式和字符串的存储模式类似。

二、如何判断机器的字节序

    通过将int强制类型转换成char单字节,通过判断起始存储位置。即等于 取b等于a的低地址部分

    联合体union的存放顺序是所有成员都从低地址开始存放,利用该特性可以轻松地获得了CPU对内存采用Little-endian还是Big-endian模式读写

三、网络字节序

   网络上传输的数据都是字节流,对于一个多字节数值,在进行网络传输的时候,先传递哪个字节也就是说,当接收端收到第一个字节的时候,它将这个字节作为高位字节还是低位字节处理,是一个比较有意义的问题; UDP/TCP/IP协议规定:把接收到的第一个字节当作高位字节看待,这就要求发送端发送的第一个字节是高位字节;而在发送端发送数据时,发送的第一个字节是该数值在内存中的起始地址处对应的那个字节,也就是说,该数值在内存中的起始地址处对应的那个字节就是要发送的第一个高位字节(即:高位字节存放在低地址处);由此可见,多字节数值在发送之前,在内存中因该是以大端法存放的; 所以说,网络字节序是大端字节序; 在实际中,当在两个存储方式不同的主机上传输时,需要借助字节序转换函数。

网络字节序与主机字节序

不同的CPU有不同的字节序类型 这些字节序是指整数在内存中保存的顺序 这个叫做主机序

最常见的有两种

1. Little endian:将低序字节存储在起始地址

2. Big endian:将高序字节存储在起始地址

LE little-endian

最符合人的思维的字节序

地址低位存储值的低位

地址高位存储值的高位

怎么讲是最符合人的思维的字节序,是因为从人的第一观感来说

低位值小,就应该放在内存地址小的地方,也即内存地址低位

反之,高位值就应该放在内存地址大的地方,也即内存地址高位

BE big-endian

最直观的字节序

地址低位存储值的高位

地址高位存储值的低位

为什么说直观,不要考虑对应关系

只需要把内存地址从左到右按照由低到高的顺序写出

把值按照通常的高位到低位的顺序写出

两者对照,一个字节一个字节的填充进去

例子:在内存中双字0x01020304(DWORD)的存储方式

内存地址

4000 4001 4002 4003

LE 04 03 02 01

BE 01 02 03 04

例子:如果我们将0x1234abcd写入到以0x0000开始的内存中,则结果为

big-endian little-endian

0x0000 0x12 0xcd

0x0001 0x23 0xab

0x0002 0xab 0x34

0x0003 0xcd 0x12

x86系列CPU都是little-endian的字节序

网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、 *** 作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用big endian排序方式。

为了进行转换 bsd socket提供了转换的函数 有下面四个

htons 把unsigned short类型从主机序转换到网络序

htonl 把unsigned long类型从主机序转换到网络序

ntohs 把unsigned short类型从网络序转换到主机序

ntohl 把unsigned long类型从网络序转换到主机序

在使用little endian的系统中 这些函数会把字节序进行转换

在使用big endian类型的系统中 这些函数会定义成空宏

同样 在网络程序开发时 或是跨平台开发时 也应该注意保证只用一种字节序 不然两方的解释不一样就会产生bug

注:

1、网络与主机字节转换函数:htons ntohs htonl ntohl (s 就是short l是long h是host n是network)

2、不同的CPU上运行不同的 *** 作系统,字节序也是不同的,参见下表。

处理器 *** 作系统 字节排序

Alpha 全部 Little endian

HP-PA NT Little endian

HP-PA UNIX Big endian

Intelx86 全部 Little endian <-----x86系统是小端字节序系统

Motorola680x() 全部 Big endian

MIPS NT Little endian

MIPS UNIX Big endian

PowerPC NT Little endian

PowerPC 非NT Big endian <-----PPC系统是大端字节序系统

RS/6000 UNIX Big endian

SPARC UNIX Big endian

IXP1200 ARM核心 全部 Little endian

  网络字节序与大小端相辅相成,共同作用使 *** 作任务完成。

 由于不同的系统会有不同的模式,为了统一,规定在网络传输中使用大端模式,这就是网络字节序。统一将网络上传输的字节序采用同一种模式,这样收发数据时,就会根据主机对应的模式是否和网络字节对应的模式一致,来判断是否需要进行转换。这样即使不同的设备使用不同的模式,网络传输不会出现问题。

inet_addr函数也是转换为网络字节序,htons的参数是u_short 也就是16位的短整型,而你的ip是一个字符串"132241510" 显然不能用htons函数,而inet_addr也是专用于转换这种ip字符串的。

在初学网络编程的时候,最好先问怎么做,别问为什么,htons就是用来转换端口的,inet_addr就是用来转换ip字符串的,就该这样做。

而且最终都转换成为了网络字节序,所以你的问题为何不需要转换成网络字节序是有错误的。

推荐你看一本书 《unix网络编程》。 直接跳到第二部分开始,从零教你网络编程,这些函数是最基本的函数。

众所周知,计算机采用二进制的计算方式,一个字节占8位(为什么是8位不是9位10位?大家可以自行探讨),不管任何数据,,文字,声音等等,都要转换成具体的数值,最终转换成二进制数据,计算机才能处理,这个过程就是编码,本文所说的编码只是针对文字编码的介绍。

现代计算机技术起源于美国,编码自然也是起源于美国, AscII (American Standard Code for Information Interchange)码就是第一套通用的计算机编码,它包含了英文字符,阿拉伯数字和一些常用符号,一共128个,占一个字节,第一位补0,例如常用的大写字母A是65(01000001),小写字母a是97,所以在JAVA里我们可以这样进行大小写转换:

从字面上来理解,字符集是一个包含指定字符的集合,而编码是把文字转换成对应的数字码,确实也是这样,像AscII码,他包含了128个特定字符,并且为每个字符指定了一个序号,可以称之为字符集,编码则是像查字典一样,从字符集中查到对应的序号,再把序号按编码规则转换成具体的数值,称之为编码。AscII码比较简单,只占了一个字节,他的编码结果和码表的序号值是一样的,所以它的字符集和编码的概念区分并不严格。

随着计算机技术的发展,AscII码只能用于拉丁文字符的限制,严重影响了非英语系国家的使用,所以,各个国家和地区分别发展出了对应本地语言的编码方式,GB2312就是中国国家标准总局制定的汉字字符集标准码,GB是国标的意思。实际上,GB2312除了中文以外,还包含了拉丁字符,希腊字符,日文,俄语等等常见字符。

GB2312占据两个字节,也就是说他能容纳的字符数量为 2 16 一共65536个。为了便于管理,GB2312将所有字符分成了若干个96字符的组,每个组称为区,字符所在的位置称为区位,这样,每个字符都有了对应的区位码。例如,汉字"安"所在的区为第16区,位置序号是18,他的区位码就是1618,有了区位码以后怎样才能转换成编码呢? 很简单,把区位码分开,区号和位置序号分别加上 0xA0,就是对应的编码了。所以"安"的GB2312编码就是 0xA0+16 0xA0+18 = 0xB0B2。

到这里,GB2312基本介绍完了,但是还有一个问题,AscII码在GB2312里是怎么处理的?实际上,GB2312兼容了AscII码,上边提到了,GB2312编码是区位码分别加A0得到的,A的编码是1010,也就是说,GB2312的编码必定是1开头的,而AscII码则是0开头的,这样就简单了,遇到1开头的编码,则按GB2312解码,遇到0开头的则按AscII解码。

GBK是GB2312的升级版,不止包含常用汉字,还包含了繁体,部首,生僻字等等,几乎可以满足所有使用汉字的场景。

Unicode是国际编码组织制定的可以容纳世界上所有文字和符号的字符编码方案,范围从0 - 0x10FFFF,分为17组,每个组称为一个平面(plane),每个平面包含65536个字符,实际上目前只用到了少数平面,比如最常用的基本平面(BMP),范围从0-0xFFFF其他的从 0x010000 - 0x10FFFFFF 则称为辅助平面(SMP),实际上在我们的日常使用中BMP基本上能满足所有要求。

Unicode包含了全世界日常使用的几乎所有字符,例如汉字"安",他的Unicode码是0x5B89。

什么是utf编码?上边介绍了Unicode,它是一个字符集,规定了每个字符对应的数值,utf则是具体的实现方式,用各种方法来存储字符对应的数值,而根据各种实现方式的不同,又分为utf-8/16/32。

utf8是变长编码,如果是1字节,它和Ascall码是一样的,多字节时第一字节的第一位开始填1,有几个1表示占几个字节,比如110x xxxx表示两个字节,第二个字节开始一直到结束,都是10开头,完整的编码如下:

同样拿汉字"安"来说,它的Unicode码是0x5B89,转换成2进制填充到utf-8的空位里去,多余的位置补0得到结果:0xE5AE89。

现在我们再看一下字符集和编码,就比较清楚了,Unicode是字符集,utf-8编码则是该字符集的一种实现方式,他们并不是同一个概念。

再来看一下utf-16编码,utf-16的长度固定为2个或者4个字节,通常我们使用2个字节就可以了,它对应的就是Unicode中的基本平面BMP,编码就是Unicode码,不足2个字节的位数在前边补0,同样是汉字"安",它的Unicode码是0x5B89,所以utf-16码也是0x5B89。所以AscII码也会占据两个字节,会有一部分空间浪费。编码Unicode辅助平面的字符时,utf-16占用4个字节,平时几乎用不到,所以具体的编码规则就不做介绍了。

utf-32编码固定占用4个字节,他对应的是全部Unicode码,这种编码方式基本用不到,也不需要深入了解。

这几个词平时出现的频率比较少一些,LE表示Little Endian,小端序,BE表示Big Endian,大端序,分别代表了计算机领域数据存储的两种方式。

大端序:

小端序:

实际上我们在日常使用过程中不需要关心当前计算机使用的是那种方式。但在UTF-16编码时,它也有大小端序两种编码方式,例如0x5E89,大端序值为0x5E89,小端序则要反过来表示为0x895E,为了区分这两种方式,在采用UTF-16编码时,在数据流的开始添加了一个统一的标识,0xFEFF表示大端序,对应的编码是utf-16be,0xFFFE表示小端序,对应的编码是utf-16be,这个表示就是BOM。

BOM全称Byte Order Mark,字节序标记,除了utf-16之外,utf-8也可以添加bom,它的bom固定为0xEFBBBF,选择编码方式为utf-8 with bom时,生成的文件流中就会出现这个bom。为什么utf-8可以不需要bom呢,因为utf8是变长的,它根据第一个字节信息判断每个字符的长度,不存在正反顺序的问题,我们日常使用的utf-8都是不带bom的。

看完了字符编码的介绍,这里有一个问题,java里的char类型能不能存储中文字符?

java里char占了两个字符,很容易得出结论,如果采用utf-8,是不能存储中文的,其他编码方式GB2312,utf-16都可以存储中文,是这样吗?

其实没有这么简单,不管我们在编辑器里选什么编码方式,对java里的char都没有影响,实际上char对应的是Unicode的基本平面BMP。我们在浏览器里选择的编码只是对应文件的保存方式,跟char采用什么编码没有任何关系,同样的,如果我们在new一个String的时候指定了编码,这个编码也只对这一个String生效,而Java里的char是编译器里定死了的,它对应的就是BMP,也可以认为是utf-16的2字节部分。

那么ava里的char类型到底能不能存储中文字符,当然可以,但是仅对应BMP部分,各种繁体字生僻字就无能为力了。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/12188670.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-21
下一篇 2023-05-21

发表评论

登录后才能评论

评论列表(0条)

保存