Python網路位元組序和主機位元組序

2021-06-26 16:29:48 字數 3811 閱讀 2000

在c中關於網路位元組序和主機位元組序困擾了我一段時間,在python中實現位元組流的網路傳輸,必然這個問題也不可避免,但是我覺得在python中解決這個問題和演示起來比較方便一點。

我們上次用struct的pack方法實現了位元組流,那麼這裡就牽涉到乙個位元組流的位元組序問題,當乙個16位的int型資料形成01的位元組流時,是高位在前,還是低位在前?這裡分為網路位元組序,和主機位元組序。

little endian:將低序位元組儲存在起始位址

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的位元組序.

我們用python來試驗一下:

>>> from struct import *

>>> pack('@h',14)

'\x0e\x00'

>>>

int型的整數14用二進位制表示應該為0000000000001110,十六進製制的話應該為0x00\ox0e ,但是如果說是低位位元組存放低位,那麼低位位元組0x0e就應該存在低位,然後高位就存放0x00,這就是我們電腦在記憶體中存放這個數的形式。我們用pack,引數為』@h』,就是把14按照主機位元組序,以2位元組的int型存放到記憶體中的。

網路位元組順序是tcp/ip中規定好的一種資料表示格式,它與具體的cpu型別、作業系統等無關,從而可以保證資料在不同主機之間傳輸時能夠被正確解釋。網路位元組順序採用big endian排序方式。那麼如果我們要把資料流發到網路上,必須把位元組順序改為高位元組在前,低位元組在後,就是我們傳送乙個0000000000001110,我們必須先發高位元組00000000,然後在發低位元組00001110,也就是十六進製制的0x00 0x0e

在struct的pack打包中,提供了乙個』!』,來實現網路位元組序,比如同樣是上面的例子:

>>> from struct import *

>>> pack('!h',14)

'\x00\x0e'

>>> 

可以看到,確實是高位元組在前,低位元組在後了。假如我們要把這個14通過udp協議傳送給另外乙個主機,那麼我們就要用這個位元組序。

下面我看乙個具體傳輸的例子吧,基於udp的。

首先我們在server和client端都用網路位元組序來pack和unpack,我們看看結果會是什麼樣:

server端:

import socket

import struct

bufsiz=1024

addr=('localhost',2046)

recvsocket=socket.socket(socket.af_inet,socket.sock_dgram)

while true:

print 'waiting for the data'

data,addr=recvsocket.recvfrom(bufsiz)

print repr(data)

(data1,)=struct.unpack('h',data)

print repr(data1)

(data2,)=struct.unpack('!h',data)

print data2

recvsocket.close()

下面是client端:

import socket

import struct

bufsiz=1024

addr=('localhost',2046)

sendsocket=socket.socket(socket.af_inet,socket.sock_dgram)

data=struct.pack('!h',14)

print repr(data)

sendsocket.sendto(data,addr)

sendsocket.close()

我們還是在client端往server端發乙個14,int型資料,我們看看執行結果:

其中紅色命令視窗為client端,綠色是server端,可以看到14通過pack傳出去的確是高位元組在前,低位元組在後,屬於網路位元組序,而server收到的14在記憶體中也是高位元組在前,低位元組在後的,這樣我們通過unpack就能得到正確的結果。

整個過程是這樣的:

14也就是0000000000001110,用pack時候我們用的網路位元組序來存,那麼在記憶體中高位元組00000000在前,低位元組00001110在後(假如不指定用網路位元組序的話,它會顛倒)然後我們傳輸的時候,因為網路傳輸是預設高位元組在前,00000000先傳,00001110後傳,到接受端接收到的還沒有unpack的資料也就是00000000在前,00001110在後了,如果這時候我們unpack不用網路位元組序來分的話,那麼得到的結果就是錯誤的,因為那麼cpu會以為這個數不是0000000000001110而是0000111000000000.所以就不對了。

附註: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

motorola680x() 

全部 big endian

mips 

nt little endian

mips 

unix 

big endian

powerpc 

nt little endian

powerpc 

非nt 

big endian 

rs/6000 

unix 

big endian

sparc 

unix 

big endian

ixp1200 arm核心 

全部 little endian

網路位元組序和主機位元組序

不同的 cpu有不同的位元組序型別 這些位元組序是指整數在記憶體中儲存的順序 這個叫做主機序 最常見的有兩種1 little endian2 big endian le little endian 最符合人的思維的位元組序 位址低位儲存值的低位 位址高位儲存值的高位 怎麼講是最符合人的思維的位元組序...

主機位元組序和網路位元組序

1.主機位元組序和網路位元組序1 以下是從ip.h和tcp.h取的,但bsd和linux用的名稱有些不一樣主要是tcp不一樣 struct ip struct tcphdr 我所理解的big序和little序的區別 1 存整數的時候 uint32 t a 1574 1574 0x626 big序 0...

網路位元組序和主機位元組序

1.網路傳資料的時候是乙個位元組乙個位元組的傳.字串裡的每乙個字元只用乙個位元組 前面的就先傳 接收的後再解釋的時候也是按順序來 所以字串沒有網路位元組序的分別.2.網路位元組序預設是大端,也就是說任何機器如果收到乙個 int型的 4個位元組,那麼這個機器就會認為第乙個位元組是最高位,最後乙個位元組...