Python 解析 Socket 数据流异常 bytes 问题 -- 2019-03-12
python 在通过 socket 发送数据时, 英文字符转义后为原来本身的字符, 占一个字节(如: s 转移后为 s), 而中文字符在转义后需要二个字节来标识一个中文字符(如: 钟转义后为 \ x92\x9f). 在发送端是不存在问题的, 而发生问题的主要是在 socket 客户端. 因为客户端在接受数据流时, 每次接受都是有字节限制, 就会出现一个中文字符分两次接受, 从而导致每次接受的流在转义成字符时报错 UnicodeDecodeError.
当前有数据流:
bmsg = b'\xe5\x88\x86\n\xe9\x92\x9f' # 分 \ n 钟
正常接受并转义为:
smsg = str(bmsg, 'utf-8') #方式一
或
smsg = bmsg.decode() # 方式二 第一参数默认 utf8, 第二参数默认 strict, 还有 ignore (忽略), replace (替代 =?)
如果现在接受到的数据流为
bmsg = b'\xe5\x88\x86\n\xe9\x92' # \x9f 作为下次接受
如何避免程序的异常退出, 有两种处理方式:
1), 数据丢失处理
此时, 如果再用正常接受方式转义 bytes 流, 就会出现 UnicodeDecodeError 异常, 为使不报异常, 我们在转义时, 通过方式二, 指定第二个参数为 ignore, 如下:
smsg = bmsg.decode('utf-8', 'ignore') # 输出: 分 \ n , 如果为 replace 则 \n 后为 ?
2), 数据流拆分, 再处理
一般 socket 服务端在发送数据时, 每个数据流是完整的, 并会以特定的字符 (如:\n) 结束一并发送. 根据这种现状, 我们在每次接受数据时, 根据这个特定字符拆分 (split) 为一个保存单个数据流的列表. 列表的第一个流可能为不完整, 把它和上次接受的流合并为一个完整的数据流并转义; 中间为可以正常转义的数据流; 最后一个流也为不完整, 保存下来, 用来拼接下次接受的流, 并重复上述操作, 这样保障了程序不会异常退出, 也保障数据的完整性. 大致代码如下:
数据接受情况: 第一次接受 msg1 = b'\xe5\x88\x86\n\xe9' ; # 钟 被拆分成 \xe9 和 \x92\x9f
第二次接受 msg2 = b'\x92\x9f_stone\n'
- init_msg = b'' # 初始化流
- while True:
- msg = soc.recv(128) # 接受数据
- init_msg += msg
- msg_arr = init_msg.split(b'\n') # 注意此处的 b'\n' , 因为被拆分的为 bytes 串, 所以也要用 bytes 串来拆分
- init_msg += msg_arr[-1]
- msg_arr.remove(msg_arr[-1])
- for i in range(len(msg_arr)):
- string = msg_arr[i].decode('utf-8')
- print(string)
来源: http://www.bubuko.com/infodetail-2985006.html