python- socket通訊 以16進位制的資料進行傳遞與解析
阿新 • • 發佈:2019-02-18
struct.pack也就是將資料按照二進位制的格式進行傳輸 |
在網路程式設計中,利用 socket 進行通訊時,常常會用到 struct 模組,在網路通訊中,大多數傳遞的資料以二進位制流(binary data)存在。傳遞字串時無需過多擔心,但傳遞 int,char 之類的基本資料時,就需要一種機制將某些特定的結構體型別打包成二進位制流的字串,然後在進行網路傳輸,而接收端也可以通過某種機制進行解包還原出原始資料。struct 模組便提供了這種機制,該模組主要作用就是對 python 基本型別值與用 python 字串格式表示的 C struc 型別間的轉化(This module performs conversions between Python values and C structs represented as Python strings.)。 另一種使用場景在與 python 與其他語言之間資料交換時使用,例如 C++ 寫的客戶端傳送了一個 int 型(4位元組)的資料到 Python 的伺服器,Python 接收到這個資料時,需要解析成 Python 認識的整數,此時就將用到 struct 模組。 |
如果熟悉結構體中資料對齊的規則,可以合理設計結構體的結構,各成員變數的順序,使得所有的資料成員存放在連續的儲存區,而且結構體的長度等於所有成員長度之和(可以適當在尾部用字元陣列補齊,避免編譯器自動填充),這樣就方便用send函式傳送了。( 如果伺服器和客戶端都是用C/C++開發,兩端可以通過同樣結構的結構體來封包和解包,可以不考慮資料對齊的問題)下面討論的是在C++和python開發的兩端之間傳輸資料的情況:客戶端用的C++編寫,伺服器端用python編寫,相對於C++中用struct來封包和解包,python提供了struct庫實現類似的功能,最重要的三個函式是pack,unpack,calcsize,struct庫處理二進位制資料的具體用法可以參考這篇文章: 另一個考慮的問題就是進位制的轉換 |
#!/usr/bin/env python #coding:utf-8 __author__ = 'ferraborghini' from socket import * import struct #將16進位制資料當做位元組流傳遞 def dataSwitch(data): str1 = '' str2 = '' while data: str1 = data[0:2] s = int(str1,16) str2 += struct.pack('B',s) data = data[2:] return str2 if __name__ == "__main__": HOST = 'localhost' PORT = 21567 BUFSIZE = 1024 ADDR = (HOST,PORT) tcpCliSock = socket(AF_INET,SOCK_STREAM) tcpCliSock.connect(ADDR) while True: data = raw_input('>') if not data: break tcpCliSock.send(dataSwitch(data)) data = tcpCliSock.recv(BUFSIZE) if not data: break print data tcpCliSock.close()
解析報文,這時候讀入的其實相當於二進位制流,我們要做的就將二進位制流轉化為16進位制就行。
#!/usr/bin/env python
#coding:utf-8
from socket import *
from time import ctime
if __name__ == "__main__":
HOST = '' #此處為空代表可以繫結所有有效地址
PORT = 21567
BUFSIZE = 1024
ADDR = (HOST,PORT)
tcpSerSocket = socket(AF_INET,SOCK_STREAM)
tcpSerSocket.bind(ADDR)
tcpSerSocket.listen(5) #最多可以有5個連線同時進入
while True:
print 'waiting for connection...'
tcpCliSock,addr = tcpSerSocket.accept()
print '...connected from:',addr
while True:
data = tcpCliSock.recv(BUFSIZE)
print data.encode('hex')
if not data:
break
tcpCliSock.send('[%s] %s'%(ctime(),data))
# tcpCliSock.close() #如果接收完,就斷開的話,下次再發送就會報錯,書本上有問題
tcpSerSocket.close()
專案開發中的一個例子:控制的是USR-R16-T繼電器燈的通斷
#將16進位制資料當做二進位制位元組流傳遞
def dataSwitch(data):
str1 = ''
str2 = b''
while data:
str1 = data[0:2]
print(str1)
s = int(str1,16)
str2 += struct.pack('B',s)
data = data[2:]
return str2
'''
req = struct.pack('7B', int('61', 16), int('64', 16), int('6D',16), int('69',16), int('6E',16), int('0D',16), int('0A',16)) #將16進位制資料轉換為10進位制,再打包
client.send(req)
data = client.recv(8096)
print ('Server send information : %s' % data.decode('utf-8'))
ss = dataSwitch('61646D696E0D0A')
print(ss)
client.send(ss)
data = client.recv(8096)
print ('Server send information : %s' % data.decode('utf-8'))
'''
#從終端獲取16進位制字串,然後轉換為二進位制的位元組流用於網路傳輸
while True:
msg = input('-->').strip()
print(type(msg))
if len(msg)==0:continue
client.send(dataSwitch(msg))
#print(dataSwitch(msg))
#client.send(msg.encode('utf-8'))
#client.send(msg)
data = client.recv(8096)
print(data)
#print ('Server send information : %s' % data[0:2].decode('utf-8'))
sk_obj.close()