2010-01-10 4 views
17

내가 데이터를 역 직렬화 Google의 프로토콜 버퍼를 사용하는 응용 프로그램을 작성하려고 해요 통해 전송되는 데이터를 역 직렬화하는 파이썬과 구글의 프로토콜 버퍼를 사용하는 방법 TCP 연결을 통해 (프로토콜 버퍼를 사용하여 다른 응용 프로그램에서 전송). 문제는 Python의 프로토콜 버퍼가 문자열의 데이터를 deserialize 할 수있는 것처럼 보입니다. TCP는 잘 정의 된 메시지 경계가없는 내가받을려고 메시지 중 하나가 반복되는 필드를 가지고 있기 때문에, 나는 시도하고 마지막으로 직렬화 할 문자열을 전달하기 전에받을 수있는 데이터의 양을 알 수 없습니다. 파이썬에서이 작업을 수행하는 좋은 사례는 TCP

이 있습니까?

답변

36

그냥 소켓에 직렬화 된 데이터를 작성하지 마십시오. 먼저 직렬화 된 객체의 길이를 포함하는 고정 크기 필드를 보냅니다.

송신 측

은 대략 다음과 같습니다

socket.write(struct.pack("H", len(data)) #send a two-byte size field 
socket.write(data) 

그리고 recv'ing 측과 같이된다 : 이것은 소켓 프로그래밍에 대한 일반적인 디자인 패턴입니다

dataToRead = struct.unpack("H", socket.read(2))[0]  
data = socket.read(dataToRead) 

합니다. 당신처럼 보이는 회선을 통한 메시지 형식으로 끝낼

type = socket.read(1)         # get the type of msg 
dataToRead = struct.unpack("H", socket.read(2))[0] # get the len of the msg 
data = socket.read(dataToRead)      # read the msg 

if TYPE_FOO == type: 
    handleFoo(data) 

elif TYPE_BAR == type: 
    handleBar(data) 

else: 
    raise UnknownTypeException(type) 

: 당신의 수신 측이 무언가 같이가되도록 대부분의 디자인뿐만 아니라 타입 필드를 포함하는 오버 - 더 - 와이어 구조를 확장

struct { 
    unsigned char type; 
    unsigned short length; 
    void *data; 
} 

예기치 않은 요구 사항에 대해 와이어 프로토콜을 미래에 대비할 수있는 적절한 작업을 수행합니다. 이것은 Type-Length-Value 프로토콜로, 네트워크 프로토콜에서 반복해서 찾을 수 있습니다.

+1

+1. 고맙습니다!! – jathanism

+2

'struct.pack ("H", len (data))'을 사용하면 중요한 결과가 발생합니다 : 데이터는 65536 바이트 이하 여야합니다. 'Q'(최대 크기 = 18000 페타 바이트) 대신 '부호없는 long long'을 사용하여 데이터의 최대 허용 크기를 늘릴 수 있습니다. – Flimm

4

J.J.의 (완전히 올바른) 답변에서 protobuf 라이브러리는 입니다. 메시지가 얼마나 오래 지속되는지 알아 내거나 어떤 유형의 protobuf 객체가 전송되는지 알아 내려고합니다 *. 따라서 데이터를 보내는 다른 애플리케이션은 이미 이와 같은 작업을 수행하고 있어야합니다. 나는이 작업을 수행했다 때

, 나는 조회 테이블 구현 :

messageLookup={0:foobar_pb2.MessageFoo,1:foobar_pb2.MessageBar,2:foobar_pb2.MessageBaz} 

을 ... 그리고 본질적으로 무엇을 J.J.했다 하지만 도우미 함수가 있습니다.

def parseMessage(self,msgType,stringMessage): 
     msgClass=messageLookup[msgType] 
     message=msgClass() 
     message.ParseFromString(stringMessage) 
     return message 

... 문자열을 protobuf 객체로 바꾸기 위해 호출했습니다. 단일 메시지에 대한 하나의 TCP 연결을 사용 어디는 (단순한 경우를이기는하지만) 고려 컨테이너 메시지

+0

두 답변 모두 좋지만 캡슐화되지 않은 frymasters는 (나에 따르면) 앞으로 나아갈 길입니다. –

0

내부의 또 다른 측면을 특정 메시지를 캡슐화하여 피해 갈 수 있다고 생각

(*)입니다 . 이 경우, 같은 당신이 예상 메시지가 무엇인지 (또는 런타임에서 메시지 유형을 결정하기 위해 Union Types를 사용), 당신은 '시작'구분 기호와 같은 연결 close 이벤트를 오픈 TCP 연결을 사용할 수 있습니다 최종 분리 문자. 이렇게하면 전체 메시지를 신속하게 수신 할 수있는 이점이 있습니다 (반면에 TCP 스트림은 전체 메시지 수신을 지연 시킴). 이렇게하면 TCP 연결의 수명이 프레임 자체처럼 작동하므로 명시적인 대역 내 프레이밍이 필요하지 않습니다. 믿을 수 없을만큼 상세하고 멋진 답변을