2012-07-02 164 views
3

我在Python中有一臺機器的控制系統,目前看起來大致是這樣的最簡單的蟒蛇網絡通訊

goal = GoalState() 
while True: 
    current = get_current_state() 
    move_toward_goal(current,goal) 

現在,我想在通過網絡來控制機器的能力增加。我想寫的代碼會是這樣的:

goal = GoalState() 
while True: 
    if message_over_network(): 
     goal = new_goal_from_message() 
    current = get_current_state() 
    move_toward_goal(current,goal) 

什麼會加入這種網絡功能爲我的應用程序的最簡單,最Python的方式?插座可以工作,認爲他們並不特別感覺Pythonic。我已經看過XMLRPC和Twisted,但他們似乎都需要對代碼進行重大修改。我也看了看ØMQ,但感覺就像我添加了一個外部依賴關係,沒有提供我沒有用過的任何插件。

我並不反對使用上面提到的任何系統,因爲我認爲是失敗可能是我的誤解。我只是很好奇處理這個簡單的常見問題的習慣方式。

回答

6

的是,你需要在決定至少兩個問題:

  1. 如何交換信息?
  2. 以什麼格式?

關於1. TCP套接字是最低級別,您需要處理低級別的事情,如識別消息邊界。此外,只有連接沒有重置(由於例如臨時網絡故障),TCP連接才能爲您提供可靠的傳輸。如果希望應用程序在TCP連接重置時正常恢復,則需要實現某種形式的消息確認以跟蹤需要通過新連接重新發送的內容。 OMQ爲您提供比純TCP連接更高的抽象級別。你不需要處理一個字節流,而是處理整個消息。它仍然不能給你可靠的交付,消息可能會丟失,但它提供了幾種可用於確保可靠交付的通信模式。 0MQ也是高性能的,IMO是個不錯的選擇。

關於2,如果不需要與其他語言的互操作性,Pickle是一個非常方便和Pythonic的選擇。如果需要互操作性,可以考慮使用JSON,或者如果性能問題,則可以使用二進制格式,例如Google協議緩衝區。最後的選擇需要最多的工作(你需要在.idl文件中定義消息格式),這絕對不會感覺到Pythonic。

看看消息的交換(任何可序列化Python對象)在一個普通的插座怎麼能是這樣的:

def send(sockfd, message): 
    string_message = cPickle.dumps(message) 
    write_int(sockfd, len(string_message)) 
    write(sockfd, string_message) 

def write_int(sockfd, integer): 
    integer_buf = struct.pack('>i', integer)  
    write(sockfd, integer_buf) 

def write(sockfd, data): 
    data_len = len(data) 
    offset = 0 
    while offset != data_len: 
     offset += sockfd.send(data[offset:]) 

不壞,但你可以看到有處理消息長度的序列化相當低的水平。

,並接收這樣的消息:

def receive(self): 
    message_size = read_int(self.sockfd) 
    if message_size == None: 
     return None 
    data = read(self.sockfd, message_size) 
    if data == None: 
     return None 
    message = cPickle.loads(data) 
    return message 

def read_int(sockfd): 
    int_size = struct.calcsize('>i') 
    intbuf = read(sockfd, int_size) 
    if intbuf == None: 
     return None 
    return struct.unpack('>i', intbuf)[0] 

def read(sockfd, size): 
    data = "" 
    while len(data) != size: 
     newdata = sockfd.recv(size - len(data)) 
     if len(newdata) == 0: 
      return None 
     data = data + newdata 
    return data 

但這並不優雅地處理錯誤(不嘗試確定哪些郵件已成功交付)。

+0

其實,0mq確實給你可靠的交付,如果你使用一個代理(如RabbitMQ的),它支持。 –

+0

有一個二進制JSONish格式(明顯是BSON:-P),它是跨語言的(例如由MongoDB使用),並且是靈活性(protobufs不給你的)和解碼速度(JSON是合理的不好)。 –

2

如果您熟悉套接字,我會考慮SocketServer.UDPServer(請參閱http://docs.python.org/library/socketserver.html#socketserver-udpserver-example)。 UDP絕對是最簡單的消息傳遞系統,但顯然你必須處理一些事實,即一些消息可能會丟失,重複或按順序傳遞。如果你的協議非常簡單,處理起來相對容易。好處是你不需要任何額外的線程,也不需要外部依賴。如果你的應用程序沒有會話的概念,它也可能是非常好的選擇。

可能是一個好的開始,但有更多的細節被認爲是不包括在你的問題。我也不會擔心這個事實,那個套接字並不是Pythonic。無論如何,最終你會使用套接字,有人會爲你包裝它,你將被迫學習框架,最好的情況下可能會滿足你的要求。

(請注意,我的意見是很大的偏見,因爲我愛處理原始套接字。)