python中字符,字节,编码格式等问题总结
一直以来,对python中的字符,字节,编码格式理解的懵懵懂懂的,遇到问题总是搞不清楚,最近看一些网络传输方面的知识时,刚好要用到这些知识,总结一下以备以后复习。
byte
首先说byte,也叫字节,一个字节是8个bit。在python中,最小的数据存储单位就是字节,ASCII码中字符在python中都是占一个字节的存储位。
英文字符和字符串
英文字符都包含在ASCII编码中,所以所有的英文字符都是占1个字节的,(注意字符和单词的区别)
s= 'a'
print(s.encode('utf8'))
print(s.encode('gbk'))
print(len(s.encode('gbk')))
# 结果
b'a'
b'a'
1
这里看到我们采用分别utf8
和gbk
两种编码方式将字符串s(python中字符串和字符不区分,这个和其他编程语言的string和char 是有区别的)进行编码,得出的字节码都是b'a'
,这个前缀b
就表示这是一个byte类型的数据。长度是1,也就是占一个字节。如果将a
改成apple
结果是什么,你们可以自己试验。
汉字
因为计算机是美国人发明的,所以他们的英文字符集就很好处理,但是汉字的字符在计算机中应该怎么保存呢?这里就牵扯到了编码和解码,针对汉字的编码最常用的有utf8
和gbk
,在网络传输或者字符存储的时候就需要把字符先编码成字节码,然后再发送/存储。在接收或读取的时候进行解码。
han = '中'
print(len(han))
print(han.encode('utf8'))
print(han.encode('gbk'))
print(len(han.encode('utf8')))
print(len(han.encode('gbk')))
# 结果
1
b'\xe4\xb8\xad'
b'\xd6\xd0'
3
2
-
对照这个例子我们详细讲解一下,变量
han
是一个汉字字符串,第2行的输出结果是1,也就是说这个字符串的长度是1,这里汉字和英文字符的字符串长度都是一样的,简单点讲就是数单个字符的个数,就是字符串长度。 -
第3行就汉字进行了
utf8
编码,第4行是gbk
编码,将中转成了字节码,但是从第9,10行的输出来看,它们完全不同,也就是说不同的编码方式对同一个字的编码结果是完全不同的。 -
第5,6行分别打印两种编码方式下一个汉字所占的字节长度,从第11,12行就能看出,一个汉字如果采用
utf8
编码时,占3个字节,而采用gbk
编码时只占了2个字节。所以说如果一大段数据如果都是中文字符的话,采用gbk
编码将会大大节省存储空间或者网络带宽。但是还是不建议你这么做,因为考虑到兼容性,现在普遍的编码方式都是utf8
最后,** 切记!!!**解码就是对编码的逆过程,所以采用了什么方式编码,就必须用同样的方式进行解码,否则肯定会报错。
数字(整型)
在网络传输中对数字也是编码成字节码进行传输的。int
型字符直接调用int.to_bytes()
方法进行编码
i = 65
print(i.to_bytes(4,byteorder='big',signed=False))
print(i.to_bytes(8,byteorder='big',signed=False))
# 结果
b'\x00\x00\x00A'
b'\x00\x00\x00\x00\x00\x00\x00A'
to_bytes()
方法中需要传入3个参数- 第一个参数是字节长度,也就是说
65
这个数字你需要编码成占多少个字节长度的字符? - 第二个参数表示的字节序是什么,这里有
big
和little
两种选项(大端和小端),大端和小端不懂的可以自行度娘,这里不做展开 - 第三个参数表示是无符号数还是有符号数,这里有符号和无符号也不做展开,具体请百度C语言的
signed
和unsigned
- 第一个参数是字节长度,也就是说
这样就完成了对整型数据的编码,解码也是逆序,使用int.from_bytes()
方法进行解码:
i = 65
i_byte_4 = i.to_bytes(4,byteorder='big',signed=False)
print(i_byte_4)
i_byte_8 = i.to_bytes(8,byteorder='big',signed=False)
print(i_byte_8)
i_decode_4 = int.from_bytes(i_byte_4,byteorder='big',signed=False)
print(i_decode_4)
i_decode_8 = int.from_bytes(i_byte_8,byteorder='big',signed=False)
print(i_decode_8)
# 结果
b'\x00\x00\x00A'
b'\x00\x00\x00\x00\x00\x00\x00A'
65
65
需要特别注意的是:解码时,from_bytes()
中传入的后两个个参数要和to_bytes()
严格对应,否则解码肯定出错
网络数据包的编解码
-
数据包的收发流程
- 发送端 当客户端给服务端发送数据包的时候一般先发送数据的长度,然后再发送数据包内容
- 接收端 接收端接到第一包数据是数据包的长度,根据数据包的长度再接收数据包长度个字节的数据,然后根据协议定义就能解出数据包的内容 -
数据包结构
- 数据包一般的结构会包括,包头(数据长度4字节+数据包类型2字节+数据包加密类型1字节+保留字段1字节)+ 包内容(N字节)
- 当接收端收到第一包数据,解出包长度以后,根据包长度接收包长度个字节的数据,然后根据上面的协议,逐段切片分割,就可以分别得到包头和包内容
这里注意的是,网络中发送的数据包都是字节码,所以在发送的时候,对不同的数据格式就要进行数据编码,而在接收的时候同样按照接收的数据的编码方式进行解码,这样就能得到原始数据。