2017-03-14 77 views
-1

我通過套接字接口從應用程序(server)以C寫入數據。發佈的數據具有以下結構。我正在用Python編寫的客戶端接收數據。如何解開另一個結構內的C風格結構?

struct hdr 
{ 
    int Id; 
    char PktType; 
    int SeqNo; 
    int Pktlength; 
}; 

struct trl 
{ 
    char Message[16]; 
    long long info; 
}; 

struct data 
{ 
    char value[10]; 
    double result; 
    long long count; 
    short int valueid; 
}; 

typedef struct 
{ 
    struct hdr hdr_buf; 
    struct data data_buf[100]; 
    struct trl trl_buf; 
} trx_unit; 

如何unpack接收到的數據來訪問我的內部數據緩衝區?

+0

您是否通過套接字接收到一串字節? – eguaio

+0

@egaio yes.I正在接收字節串。 – Soumajit

回答

0

使用struct庫是一種可行的方法。但是,您將不得不更多地瞭解正在序列化數據的C程序。考慮hdr結構。

struct hdr header; 
send(sd, &hdr, sizeof(header), 0); 

然後你的客戶不能安全解釋,因爲存在結構成員之間插入的填充一個不確定的量被髮送給它的字節:如果C程序正在使用幼稚的做法發送。特別是,我期望在PktType成員之後填充三個字節。

發送二進制數據的最安全方法是讓服務器和客戶機直接序列化字節,以確保沒有附加填充並顯式地對多字節整數進行字節排序。例如:

/* 
* Send a header over a socket. 
* 
* The header is sent as a stream of packed bytes with 
* integers in "network" byte order. For example, a 
* header value of: 
* Id: 0x11223344 
* PktType: 0xff 
* SeqNo: 0x55667788 
* PktLength: 0x99aabbcc 
* 
* is sent as the following byte stream: 
* 11 22 33 44 ff 55 66 77 88 99 aa bb cc 
*/ 
void 
send_header(int sd, struct hdr const* header) 
{ /* NO ERROR HANDLING */ 
    uint32_t num = htonl((uint32_t)header->Id); 
    send(sd, &num, sizeof(num), 0); 
    send(sd, &header->PktType, sizeof(header->PktType), 0); 
    num = htonl((uint32_t)header->SeqNo); 
    send(sd, &num, sizeof(num), 0); 
    num = htonl((uint32_t)header->PktLength); 
    send(sd, &num, sizeof(num), 0); 
} 

這將確保您的客戶端可以使用struct模塊安全地對其進行解碼:

buf = s.recv(13) # packed data is 13 bytes long 
id_, pkt_type, seq_no, pkt_length = struct.unpack('>IBII', buf) 

如果您不能修改C代碼來解決序列化的不確定性,那麼你將不得不從流中讀取數據並找出C編譯器插入填充的位置,然後手動構建struct格式字符串以匹配使用填充字節格式字符忽略填充值。

我通常在Python中編寫一個解碼器類,它從套接字中讀取一個完整的值。在你的情況下,它看起來是這樣的:

class PacketReader(object): 
    def __init__(self, sd): 
     self._socket = sd 

    def read_packet(self): 
     id_, pkt_type, seq_no, pkt_length = self._read_header() 
     data_bufs = [self._read_data_buf() for _ in range(0, 100)] 
     message, info = self._read_trl() 
     return {'id': id_, 'pkt_type': pkt_type, 'seq_no': seq_no, 
       'data_bufs': data_bufs, 'message': message, 
       'info': info} 

    def _read_header(self): 
     """ 
     Read and unpack a ``hdr`` structure. 

     :returns: a :class:`tuple` of the header data values 
      in order - *Id*, *PktType*, *SeqNo*, and *PktLength* 

     The header is assumed to be packed as 13 bytes with 
     integers in network byte order. 

     """ 
     buf = self._socket.read(13) 
     # > Multibyte values in network order 
     # I Id as 32-bit unsigned integer value 
     # B PktType as 8-bit unsigned integer value 
     # I SeqNo as 32-bit unsigned integer value 
     # I PktLength as 32-bit unsigned integer value 
     return struct.unpack('>IBII', buf) 

    def _read_data_buf(self): 
     """ 
     Read and unpack a single ``data`` structure. 

     :returns: a :class:`tuple` of data values in order - 
      *value*, *result*, *count*, and *value* 

     The data structure is assumed to be packed as 28 bytes 
     with integers in network byte order and doubles encoded 
     as IEEE 754 binary64 in network byte order. 

     """ 
     buf = self._socket.read(28) # assumes double is binary64 
     # > Multibyte values in network order 
     # 10s value bytes 
     # d result encoded as IEEE 754 binary64 value 
     # q count encoded as a 64-bit signed integer 
     # H valueid as a 16-bit unsigned integer value 
     return struct.unpack('>10sdqH', buf) 

    def _read_trl(self): 
     """ 
     Read and unpack a ``trl`` structure. 

     :returns: a :class:`tuple` of trl values in order - 
      *Message* as byte string, *info* 

     The structure is assumed to be packed as 24 bytes with 
     integers in network byte order. 

     """ 
     buf = self.socket.read(24) 
     # > Multibyte values in network order 
     # 16s message bytes 
     # q info encoded as a 64-bit signed value 
     return struct.unpack('>16sq', buf) 

你要知道,這是未經測試,可能包含語法錯誤,但是這是我將如何處理這個問題。

+0

@Shawley感謝您的指導。你能不能詳細說一下關於'> 10sdIIH'和'> 16sII'? – Soumajit

+0

@Soumajit - 我添加了一些評論和文檔。我也轉換爲使用'q'來處理64位有符號值。我錯誤地認爲它只能在純模式下使用。請參閱https://docs.python.org/3/library/struct.html#format-characters –

+0

的註釋(2)@Shawley再次非常感謝。 – Soumajit

1

struct庫有你需要做的這一切。

+0

@equaio感謝您的建議。我不確定''unpack'裏面的結構體的格式說明符 – Soumajit

相關問題