標籤:python socket struct模組
最近跳槽到西安一家機器人公司,我們的產品屬於教育機器人的範疇,為了增強客戶吸引力,引進了一個智能家居公司的產品API介面,讓機器人來操作智能家居
該公司的智能家居API是自訂TCP包,即直接在TCP頭後面寫自訂資料結構:
用戶端請求下載 傢具資料庫 的格式
伺服器返回請求結果 的格式
命令字(4位元組,小端) |
payload長度(4位元組,小端) |
payload(N*1位元組) |
0x43 |
11262(尺寸很大) |
sqlite資料庫 |
預設python socket只能收發字串,需要藉助struct才能收發位元據
發送請求
cmd_word = 0x4ctx_buf = struct.pack('<I', cmd_word)sock.sendall(tx_buf)
tx_buf據struct的文檔說是其對輸入編碼產生的字串,用type(tx_buf)顯示確實是<type ‘str‘>,print tx_buf顯示字母L
但len(tx_buf) == 4, print repr(tx_buf)顯示
‘L\x00\x00\x00‘
也就是說len(‘L\x00\x00\x00‘) == 4
對於從C語言轉過來的人來說,上面情況真是理解不能,但它就是發送成功了
接收應答
fp = open('house.db', 'wb+')recv_cnt = 0while True: rx_buf = sock.recv(4096) len_buf = len(rx_buf) if len_buf ==0: break if recv_cnt == 0: cmd_word, data_len_total = struct.unpack(rx_buf[0:8]) buf = buffer(rx_buf, 8, len_buf - 8) fp.write(buf) else: buf = buffer(rx_buf) fp.write(buf) recv_cnt = recv_cnt +1
注意:
0、接收自訂幀頭時用unpack,可以獲得結構體各欄位取值
1、接收自訂幀內容(位元組流)時不用unpack,因為unpack返回的是tuple,而write不支援tuple類型
2、因為是二進位寫入,所以必須將str轉成buffer類型
3、位元據很大時,底層會拆分成多個乙太網路幀,如果你sendall後馬上recv,則可能只收到1448位元組,不要擔心,這是因為你recv時核心協議棧只有一幀這麼多資料,它全部返回給你了,滿足socket編程的標準
用struct模組實現python socket收發自訂TCP包