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)