2011년 2월 17일 목요일

[Python] struct 와 padding 에 대한 잡설

Python이 문법적이나 built-in module 지원 면에서 굉장히 편한건 사실이다. 하지만 매우 취약한 부분이 있으니 그건 binary data 엑세스가 아닐까. (뭐 대부분의 스크립팅 언어나 하이레벨 언어는 같이 가지고 있는 장점... 아니 문제 같다.)

바이너리라고 했지만 거의 byte 단위의 데이터 처리라고 하는게 맞으려나.

내 경우 socket프로그래밍을 하면서, 프로토콜의 최소화를 위해 바이트 단위 버퍼 사용하려 했으니 이게 생각처럼 쉬운게 아니었다. 특정 숫자는 1바이트, 특정 데이터는 4바이트 이런 식으로 맘대로 필드를 버퍼 내에 넣을 수가 없는 거다.

c에서는 'char *' 혹은 'unsigned char *' (혹은 [] array를 쓰든) 등 바이트 단위의 처리는 기본이다. 데이터 타입도 명확해서 sizeof로 계산해서 unsigned int든 long이든 특정 크기의 타입으로 변환해서 버퍼에 써 넣으면 endian만 주의하면 아주 편하다.

(아마도 이런 C 스러운 프로세스가 머리에 박혀있으니 어려운 듯 생각되기도 한다.)

뭐 하여간, 이럴 때를 위해서 Python에 struct 모듈이 존재한다. 물론 비트 연산을 직접 해서 리스트에 쳐박아 버리는 형태도 있지만 뭔가 잘 안되더라 -ㅁ-

struct 모듈은 특정 수치 데이터 들을 특정 포맺으로 변환해서 버퍼에 쌓아주는 pack() 그 반대의 역활인 unpack()을 보유하고 있다. 장하다!

귀찮으니 자세한 건 reference document 참고
http://docs.python.org/library/struct.html

그런데 이게 데이터마다 padding(?)을 쑤셔넣는다. 윈도우 머신에서 테스트 해 보니 4 byte 단위로 padding을 집어넣더라. 1 byte 짜리 데이터를 넣는데 4 byte가 들어가버린다. 01 을 넣었는데 01 00 00 00 이 되어버리면 기분이 왠지 더럽더라. ;;

padding은 무조건 4바이트를 맞추는게 아니라 4바이트 단위를 유지하려는 형식이다. 위의 예는 1+4byte를 pack해서 8바이트 였지만 1+1+4byte로 pack해도 8바이트가 된다. 앞의 1+1은 4byte내에 들어가니까 합쳐져 버린거다.

그래서 정확하게 byte단위 처리를 하려면 endian에 따라 pack()으로 뭉쳐놓은 데이터를 잘 잘라서 가공해야 한다. (필요없는거는 좀 버리라고!)

이게 사람 귀찮게 만드는 부분이더라. 혹시나 padding에 대한 특별한 기능이 있다면 좋겠지만 (내 고질병인 문서 대충읽기 스킬로) 문서를 읽어봐도 그런 부분은 못 찾겠다.

... 사실 padding을 있는 그대로 받아들이면 문제는 해결되는 거거든? ...

집어치워. 1바이트의 패킷요금도 아껴주고 보살펴 줘야 되는 신세거든. -_-++

ps. padding이란건 데이터 크기에 따른 pack 시의 호환성 문제를 해결하기 위한 것이므로 불평할 것이 결코 아니다. 단지, 의도에 따라 불편함이 생길수도 있다는 것.



문서에서 endian 및 padding과 관련하여 !, =, >, < 등의 prefix를 이용했을 때 padding을 붙지 않게 할 수도 있다는 친우의 제보(?)가 있었다. @은 기본값이며 padding이 붙는다고... 역시 문서를 잘 읽어봐야 된다. -ㅁ-;
>>> def hexdump(buf):
  output = ''
  for b in buf:
    output += '%02x:' % ord(b)

  return output

>>> import struct
>>> print hexdump(struct.pack('BI', 0x12, 0x34567890))
12:00:00:00:90:78:56:34:

>>> print hexdump(struct.pack('>BI', 0x12, 0x34567890))
12:34:56:78:90:
옛날에는 '>'를 붙였을 때 exception이 났었는데 왜 그런가 했더니 format을 '>B>I' 이런 식으로 적어서 그랬나보다. 하여간 첫 pack에서 12:00:00:00 에서 뒤의 00 3개가 padding이다.

댓글 없음 :