python處理二進制數據

問題

       在工作中經常會用到socket傳輸數據,例如客戶端給服務器發送數據(雙方約定了數據格式),在交測之前,自己用python寫個接受數據的server,解析下拼成的數據格式是否正確。用python寫比C語言簡單很多。

PS:實際上我是不會python的,工作中是C/C++開發,使用python純屬是爲了偷懶^_^

       舉個具體的例子:通信雙方約定的數據格式爲
          

       數據格式爲二進制的,python需要用到struct模塊處理二進制數據。struct模塊中最重要的三個函數pack(), unpack(), calcsize()。因爲struct相當於C語言中的結構體,unpack()返回的是一個元組。struct支持的格式如下表

        

        注1)q和Q只有在機器支持64位時有意義;

        注2)每個格式前可以有一個數字,表示個數;

        注3)s格式表示一定長度的字符串,4s表示長度爲4的字符串,p表示的是pascal字符串;

        注4)P用來轉換一個指針,其長度和機器字長有關;

默認情況下struct根據本地機器字節順序轉換,也可以用格式中的第一個字符來改變對齊方式。定義如下:

      

        注:無論數據包是python程序struct.pack()得到的,或者是C,C++,Java程序拼成的,只需保證client端和server端字節順序保持一致即可。

       以文章開頭的例子來說明pack()和unpack()函數:

      

        注:測試環境中中文爲utf-8編碼(python的編碼折騰了半天,也沒太懂,這裏不是重點)

        1)pack(format, v1, v2, ...)按照指定的格式(format),把數據封裝成字符串,例如

              >>s=struct.pack("2i13si6s2i", 33, 13, "www.baidu.com", 6, "冬季", 0, 0)

         2)unpack(format, string)    按照給定的格式(fmt)解析字節流string,返回解析出來的tuple,例如
              >>us=struct.unpack("2i13si6s2i", s)

          輸出結果:

              >>print us
              (33, 13, 'www.baidu.com', 6, '\xe5\x86\xac\xe5\xad\xa3', 0, 0)

                   注: 中文部分是二進制,從元組中取出來再打印

              >> print us[4]
               冬季

              注:對python下的中文編碼感興趣的同學可以研究下python環境編碼(再次說明我真的不會python! >_<)

舉個簡單的例子:

#!/usr/bin/python
import socket
import struct
import os
import time

if __name__ == "__main__":
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind(("127.0.0.1", 51001)) #本機端口號51001
    server.listen(1)
    while (1):
        conn,client = server.accept()
        conn.settimeout(5000)         #設置超時時間
        msg = conn.recv(4)            #total data length
        if len(msg) <= 0:             #接收空數據包 
            continue
        data = struct.unpack("i", msg)
        print "Recv Total length:%d"%(data[0])
        process_len = 0 
        msg = conn.recv(data[0])
        for i in range(0,4):          #循環四次,分別取 url title content author
            para = msg[process_len:(process_len + 4)] 
            if len(para) < 4:         #如果某一字段爲空,不處理
                continue
            data = struct.unpack("i", para)
            str_len = data[0]
            print "%d"%(str_len)
            para = msg[(process_len + 4):(process_len + 4 + str_len)]
            if len(para) < str_len:   #如果實際收到的字符串長度小於數據頭給的長度,不處理
                continue
            data = struct.unpack("%ds"%(str_len), para)
            print "%s"%(data[0])
            process_len = process_len + 4 + str_len 
        conn.close()

部分輸出結果:

Recv Total length:355
117
http://mamashuozhelideidamasaike.com/nikanbudaoleba.html(補齊117位)
27
【段子】老闆講笑話
186
老闆今天在辦公室給大家講了一個笑話,所有人都笑得人仰馬翻,只有小李沒笑。我笑着問他怎麼不笑,小李冷冷答道:“我已經辭職了!”
9
春秋天


參考資料:http://blog.163.com/tieying5566@126/blog/static/6421517120117342958949/



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章