pythonの中のstruct.packとstruct.unpack関数

5406 ワード

http://songpengfei.iteye.com/blog/1440637
http://blog.chinaunix.net/uid-22920230-id-3324663.html
http://blog.csdn.net/jgood/article/details/4290158
Pythonは非常に簡潔な言語であり、データのタイプの表現については、他の言語のように多くのタイプが予め定義されていません。(例えば、C璣では、形を整えただけで8種類が定義されています。)、六つの基本タイプしか定義されていません。文字列、整数、浮動小数点、元グループ、リスト、辞書です。この六つのタイプのデータを通して、私たちはほとんどの仕事を完成できます。しかし、Pythonがネットワークを介して他のプラットフォームと対話する必要がある場合、これらのデータタイプを他のプラットフォームまたは言語との間のタイプと相互変換することを考慮しなければならない。例えば、C+++で書いたクライアントから、int型(4バイト)変数のデータをPythonに書いたサーバに送信します。Pythonはこの整数を表す4バイトのデータを受信しましたが、Pythonが認識する整数にどう解析しますか?Pythonの標準モジュールstructはこの問題を解決するために使われます。
structモジュールの内容は多くないです。難しくもないです。その中で一番よく使われている方法を紹介します。
書式文字列について
Pythonマニュアルでは、C言語でよく使われるタイプのPythonタイプに対応する書式を示しています。
書式
C言語の種類
Pythonタイプ

x
pad byte
no value
 
c
char
string of length 1
 
b
signed char
インテグ
 
B
unsigned char
インテグ
 

_。Bool
ブック
 
h
ショート?ト
インテグ
 
H
unsigned shart
インテグ
 
i
要点
インテグ
 
I
unsigned int
インテグor long
 
l
long
インテグ
 
L
unsigned long
long
 
q
long long
long
 
Q
unsigned long long
long
 
f
float
float
 
d
ドビー
float
 
s
char[]
ストリングス
 
p
char[]
ストリングス
 
P
void*
long
struct.pack
struct.packは、Pythonの値をフォーマットに従って文字列に変換するために使用されます(Pythonにはバイトタイプがないので、ここの文字列をバイトストリームまたはバイト配列として理解することができます)。その関数のプロトタイプは、struct.pack(fmt,v 1,v 2,…)であり、パラメータfmtはフォーマット文字列であり、書式文字列に関する情報は以下の通りである。v 1,v 2,…は変換するpython値を表します。以下の例では、2つの整数を文字列(バイトストリーム)に変換します。
# -*- coding: UTF-8 -*-
#!/usr/bin/python
import struct  
a = 20  
b = 400  
str = struct.pack("ii", a, b) #    str        ,             (    ),          
print 'length:', len(str)  
print str  
print repr(str) 

str = struct.pack("2i", a, b) #    str        ,             (    ),          
print 'length:', len(str)  
print str  
print repr(str) 

#---- result  
#length: 8  
# ----       
#'/x14/x00/x00/x00/x90/x01/x00/x00'
#length: 8  
# ----       
#'/x14/x00/x00/x00/x90/x01/x00/x00'
「i」は、「int」に変換し、「ii」は2つのint変数があることを表します。変換を行った結果、長さは8バイト(intタイプは4バイト、2つはint 8バイト)となり、出力の結果は文字化けとなり、結果はバイナリデータとなり、文字化けとして表示されます。pythonの内蔵関数reprを使用して識別可能な文字列を取得することができ、16進数の0 x 0000014、0 x 00009はそれぞれ20および400を表す。
struct.unpack
struct.unpackのする仕事はちょうどstruct.packと反対で、バイトストリームをpythonデータタイプに変換するために使われます。その関数のプロトタイプは、struct.unpack(fmt,string)であり、この関数は元のグループに戻ります。以下は簡単な例です。
str = struct.pack("ii", 20, 400)
a1, a2 = struct.unpack("ii", str)
print 'a1:', a1
print 'a2:', a2
#---- result:
#a1: 20
#a2: 400 
注意:
もし一つの数だけあるなら、このように使います。
c,=struct.unpack(「i」,str)
さもなくば得るのは整数ではありません。
struct.csize
struct.csizeは、フォーマット文字列に対応する結果の長さを計算するために用いられ、例えば、struct.csize('ii')は、8を返す。二つのintタイプが占める長さは8バイトです。
struct.pack_into、struct.unpack_from
 この二つの関数はPythonマニュアルで紹介されていますが、どのように使用するかの例はありません。実際の応用ではあまり多く使われていません。Googleは長い間、やっと一つの例を見つけました。貼って共有してみます。
import struct  
from ctypes import create_string_buffer  
  
buf = create_string_buffer(12)  
print repr(buf.raw)  
  
struct.pack_into("iii", buf, 0, 1, 2, -1)  
print repr(buf.raw)  
  
print struct.unpack_from('iii', buf, 0)  
  
#---- result  
#'/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00'  
#'/x01/x00/x00/x00/x02/x00/x00/x00/xff/xff/xff/xff'  
#(1, 2, -1)  
クライアントサーバが受信データを送信する例:
pythonで書いたサーバ端:
import socket, struct  
  
s = socket.socket()  
s.bind(('127.0.0.1', 8000))  
s.listen(1)  
  
try:  
    while True:  
        cli, addr = s.accept()  
        data = cli.recv(100)  
  
        print "recv %d bytes" % len(data)  
        a, b, c = struct.unpack('i10sh', data)  
        print a, b, c  
  
        sdata = struct.pack('i10sh', 34, "abcdefghi\0", 65)  
        cli.send(sdata)  
finally:  
    s.close()  
C書き込みのクライアント:
/* tcp_client.c */  
#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <sys/types.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  
#include <unistd.h>  
  
typedef struct _data {  
    int a;  
    char b[10];  
    short c;  
} Data;  
  
int main()  
{  
    int client_fd;  
    struct sockaddr_in server_addr;  
  
    server_addr.sin_family = AF_INET;  
    server_addr.sin_port = htons(8000);  
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");  
    bzero(&(server_addr.sin_zero), 8);  
  
    client_fd = socket(AF_INET, SOCK_STREAM, 0);  
  
    connect(client_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));  
  
    Data d;  
    memset(&d, 0, sizeof(d));  
    d.a = 3;  
    memcpy(&d.b, "hello", 5);  
    d.c = 6;  
    send(client_fd, &d, sizeof(d), 0);  
  
    char buf[200];  
    bzero(buf, 200);  
    recv(client_fd, buf, sizeof(buf), 0);  
  
    Data* p = (Data*)&buf;  
    printf("%d %s %d
", p->a, p->b, p->c); close(client_fd); return 0; }