最简单的python网络消息传递

时间:2012-07-02 21:12:16

标签: python networking interprocess

我有一个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)

在我的应用程序中添加这种网络功能最简单,最Pythonic的方法是什么?套接字可以工作,认为他们并不特别感觉Pythonic。我看过XMLRPC和Twisted,但两者似乎都需要对代码进行重大修改。我也看过ØMQ,但感觉我正在添加一个外部依赖项,它没有提供任何我没有用套接字的东西。

我并不反对使用我在上面提到的任何系统,因为我认为失败可能是我的误解。我只是好奇地处理这个简单,常见的问题的惯用方法。

2 个答案:

答案 0 :(得分:6)

至少需要决定两个问题:

  1. 如何交换消息?
  2. 用什么格式?
  3. 关于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
    

    但是这并没有优雅地处理错误(没有尝试确定哪些消息成功传递)。

答案 1 :(得分:2)

如果您熟悉套接字,我会考虑SocketServer.UDPServer(请参阅http://docs.python.org/library/socketserver.html#socketserver-udpserver-example)。 UDP绝对是最简单的消息传递系统,但显然,您必须处理某些消息可能丢失,重复或无序传递的事实。如果您的协议非常简单,那么它的处理起来相对容易。优点是您不需要任何其他线程,也不需要外部依赖项。如果您的应用程序没有会话概念,那么它也可能是非常好的选择。

可能一开始就有好处,但还有更多细节要考虑,不包括在你的问题中。我也不会担心插座不是非常Pythonic的事实。最后你会使用套接字,有人会为你包装它们,你将被迫学习框架,在最好的情况下可能会满足你的要求。

(请注意我的意见非常偏颇,因为我喜欢处理原始套接字。)