📄 protocol.py
字号:
# # ***** BEGIN LICENSE BLOCK *****# Source last modified: $Id: protocol.py,v 1.3 2004/07/07 22:00:04 hubbe Exp $# # Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.# # The contents of this file, and the files included with this file,# are subject to the current version of the RealNetworks Public# Source License (the "RPSL") available at# http://www.helixcommunity.org/content/rpsl unless you have licensed# the file under the current version of the RealNetworks Community# Source License (the "RCSL") available at# http://www.helixcommunity.org/content/rcsl, in which case the RCSL# will apply. You may also obtain the license terms directly from# RealNetworks. You may not use this file except in compliance with# the RPSL or, if you have a valid RCSL with RealNetworks applicable# to this file, the RCSL. Please see the applicable RPSL or RCSL for# the rights, obligations and limitations governing use of the# contents of the file.# # Alternatively, the contents of this file may be used under the# terms of the GNU General Public License Version 2 or later (the# "GPL") in which case the provisions of the GPL are applicable# instead of those above. If you wish to allow use of your version of# this file only under the terms of the GPL, and not to allow others# to use your version of this file under the terms of either the RPSL# or RCSL, indicate your decision by deleting the provisions above# and replace them with the notice and other provisions required by# the GPL. If you do not delete the provisions above, a recipient may# use your version of this file under the terms of any one of the# RPSL, the RCSL or the GPL.# # This file is part of the Helix DNA Technology. RealNetworks is the# developer of the Original Code and owns the copyrights in the# portions it created.# # This file, and the files included with this file, is distributed# and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY# KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS# ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET# ENJOYMENT OR NON-INFRINGEMENT.# # Technology Compatibility Kit Test Suite(s) Location:# http://www.helixcommunity.org/content/tck# # Contributor(s):# # ***** END LICENSE BLOCK *****# """Async/sync generic protocol system. Uses mainloop.py, and cPickleto pickle and send objects across a TCP socket."""import sysimport stringimport reimport socketimport cPickleimport Queueimport mainloopimport outmsg## the passed network message objectsclass Message: def __init__(self, type): self.type = type self.data = None def __repr__(self): print 'Message %s' % (self.type) def __str__(self): print 'Message %s' % (self.type)## abstract interface for message pipesclass MessagePipe: def __init__(self): self.message_cb = None self.close_cb = None def set_message_cb(self, message_cb): self.message_cb = message_cb def set_close_cb(self, close_cb): self.close_cb = close_cb def send(self, message): pass def close(self): self.call_close_cb() def call_close_cb(self): if self.close_cb: self.close_cb(self) def call_message_cb(self, message): if self.message_cb: self.message_cb(self, message) class LocalMessagePipe(MessagePipe): def __init__(self): MessagePipe.__init__(self) self.destination_message_pipe = None ## incoming_message_queue is a thread-safe queue where ## incoming messages are placed self.incoming_message_queue = Queue.Queue(0) def set_destination_message_pipe(self, destination_message_pipe): self.destination_message_pipe = destination_message_pipe def incoming_message(self, message): self.incoming_message_queue.put(message) def send(self, message): self.destination_message_pipe.incoming_message(message) def run_incoming_queue(self): while not self.incoming_message_queue.empty(): message = self.incoming_message_queue.get() self.call_message_cb(message)class SocketMessagePipe(MessagePipe): STATE_HEADER = 0 STATE_MESSAGE = 1 message_match = re.compile('^MESSAGE BYTES (\d+)$') def __init__(self, sock): MessagePipe.__init__(self) self.sock = sock ## message recieve state information self.message_length = 0 self.state = self.STATE_HEADER ## send and recieve buffers self.recv_len = 0 self.recv_buff = [ "" ] self.send_pos = 0 self.send_buff = '' ## add socket to network engine self.sock.setblocking(0) mainloop.add_read_cb(self.sock, self.P_sock_read_cb, None) def send(self, message): ## add message to send buffer self.send_buff = self.send_buff[self.send_pos:]+self.P_encode(message) self.send_pos=0 ## sanity check if not len(self.send_buff): return try: send_len = self.sock.send(self.send_buff) except socket.error, (err_number, err_string): print 'socket.error: %s %d' % (err_string, err_number) self.close() return ## zero bytes written is EOF, socket is closed if not send_len: self.close() return ## wrote the whole buffer if send_len == len(self.send_buff): self.send_buff = '' mainloop.remove_write_cb(self.sock) return ## schedule a write-ready callback to write the rest of the data if send_len < len(self.send_buff): self.send_buff = self.send_buff[send_len:] mainloop.add_write_cb(self.sock, self.P_sock_write_cb) return def close(self): mainloop.remove_read_cb(self.sock) mainloop.remove_write_cb(self.sock) self.call_close_cb() def P_sock_write_cb(self, sock): try: send_len = self.sock.send(self.send_buff[self.send_pos:self.send_pos+8192]) except socket.error, (err_number, err_string): print 'socket.error: %s %d' % (err_string, err_number) self.close() return ## zero bytes written is EOF, socket is closed if not send_len: self.close() return ## wrote the whole buffer if send_len + self.send_pos == len(self.send_buff): self.send_buff = '' self.send_pos = 0 mainloop.remove_write_cb(self.sock) else: self.send_pos = self.send_pos + send_len return def P_sock_read_cb(self, sock): try: buff = self.sock.recv(8192) except socket.error: self.close() return ## check for socket EOF if not buff: self.close() return self.recv_buff.append(buff) self.recv_len = self.recv_len + len(buff) ## loop until the buffer is empty or there is ## not enough data to decode a complete message while self.recv_len: ## read the header for an incoming message if self.state == self.STATE_HEADER: if not self.P_read_header(): break ## read and decode the message if self.state == self.STATE_MESSAGE: if not self.P_read_message(): break def P_read_header(self): while 1: line = self.P_read_line() if not line: return 0 mgroup = self.message_match.match(line) if mgroup: break ## message line, get message length self.message_length = string.atoi(mgroup.group(1)) self.state = self.STATE_MESSAGE return 1 def P_read_message(self): if self.recv_len < self.message_length: return 0 ## decode the message if len(self.recv_buff) > 1: self.recv_buff = [ string.join(self.recv_buff,"") ] message = self.P_decode(self.recv_buff[0][:self.message_length]) ## remove the message from the buffer self.recv_buff[0] = self.recv_buff[0][self.message_length:] self.recv_len = len(self.recv_buff[0]) self.state = self.STATE_HEADER ## deliver the message if we were sucessful in decoding it if message: self.call_message_cb(message) return 1 def P_read_line(self): if len(self.recv_buff) > 1: self.recv_buff = [ string.join(self.recv_buff,"") ] index = string.find(self.recv_buff[0], '\r\n') if index < 0: return None line = self.recv_buff[0][:index] self.recv_buff[0] = self.recv_buff[0][index+2:] self.recv_len = len(self.recv_buff[0]) return line ## encode/decode message objects into network form def P_encode(self, message): buff = '' try: buff = cPickle.dumps(message, 1) buff = 'MESSAGE BYTES %d\r\n%s' % (len(buff), buff) except: pass return buff def P_decode(self, data): message = None try: message = cPickle.loads(data) except: pass return message## entrypointsdef CreateMessage(type): return Message(type) def CreateSocketMessagePipe(sock): return SocketMessagePipe(sock)def CreateLocalMessagePipePair(): mp1 = LocalMessagePipe() mp2 = LocalMessagePipe() mp1.set_destination_message_pipe(mp2) mp2.set_destination_message_pipe(mp1) return mp1, mp2
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -