简体   繁体   English

最简单的python网络消息传递

[英]Simplest python network messaging

I have a machine control system in Python that currently looks roughly like this 我有一个Python的机器控制系统,目前看起来大致如此

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

Now, I'm trying to add in the ability to control the machine over the network. 现在,我正试图增加通过网络控制机器的能力。 The code I want to write would be something like this: 我想写的代码是这样的:

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

What would be the simplest and most Pythonic way of adding this sort of networking capability into my application? 将这种网络功能添加到我的应用程序中最简单,最Pythonic的方法是什么? Sockets could work, thought they don't particularly feel Pythonic. 套接字可以工作,认为他们并不特别感觉Pythonic。 I've looked at XMLRPC and Twisted, but both seemed like they would require major revisions to the code. 我看过XMLRPC和Twisted,但两者似乎都需要对代码进行重大修改。 I also looked at ØMQ, but it felt like I was adding an external dependency that didn't offer anything that I didn't already have with sockets. 我也看过ØMQ,但感觉我正在添加一个外部依赖项,它没有提供任何我没有使用套接字的东西。

I'm not opposed to using any of the systems that I've addressed above, as what I believe to be failings are probably misunderstandings on my part. 我并不反对使用我上面提到的任何系统,因为我认为失败可能是我的误解。 I'm simply curious as to the idiomatic way of handling this simple, common issue. 我只是好奇地处理这个简单,常见的问题的惯用方法。

The are at least two issues you need to decide on: 至少有两个问题你需要决定:

  1. How to exchange messages? 如何交换消息?
  2. In what format? 用什么格式?

Regarding 1. TCP sockets are the lowest level and you would need to deal with low level things like recognizing messages boundaries. 关于1. TCP套接字是最低级别,您需要处理低级别的事情,如识别消息边界。 Also, TCP connection gives you reliable delivery but only as long as the connection is not reset (due to for example a temporary network failure). 此外,只要连接未重置(由于例如临时网络故障),TCP连接就可以为您提供可靠的交付。 If you want your application to gracefully recover when a TCP connection resets, you need to implement some form of messages acknowledgements to keep track what needs to be resend over the new connection. 如果希望应用程序在TCP连接重置时正常恢复,则需要实现某种形式的消息确认,以跟踪需要通过新连接重新发送的内容。 OMQ gives you higher level of abstraction than plain TCP connection. OMQ为您提供比纯TCP连接更高级别的抽象。 You don't need to deal with a stream of bytes but with whole messages. 您不需要处理字节流,但需要处理整个消息。 It still does not give you reliable delivery, messages can get lost, but it gives several communication patterns that can be used to ensure reliable delivery. 它仍然不能为您提供可靠的交付,消息可能会丢失,但它提供了几种可用于确保可靠交付的通信模式。 0MQ is also highly performant, IMO it is a good choice. 0MQ也是高性能的,IMO是一个不错的选择。

Regarding 2, if interoperability with other languages is not needed, Pickle is a very convenient and Pythonic choice. 关于2,如果不需要与其他语言的互操作性,那么Pickle是一种非常方便和Pythonic的选择。 If interoperability is needed, you can consider JSON, or, if performance is an issue, binary format, such as Google protocol buffers. 如果需要互操作性,您可以考虑JSON,或者,如果性能有问题,可以考虑二进制格式,例如Google协议缓冲区。 This last choice would require the most work (you'll need to define messages formats in .idl files) this would definitely not feel Pythonic. 这最后的选择需要最多的工作(你需要在.idl文件中定义消息格式)这绝对不会感觉到Pythonic。

Take a look how exchange of messages (any serializable Python object) over a plain socket can look like: 看一下普通套接字上的消息交换(任何可序列化的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:])

Not bad, but as you can see having to deal with serialization of a message length is quite low level. 还不错,但正如你所看到的,必须处理消息长度的序列化是相当低的水平。

And to receive such message: 并收到这样的消息:

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

But this does not gracefully deal with errors (no attempt to determine which messages were delivered successfully). 但这并没有优雅地处理错误(没有尝试确定哪些消息成功传递)。

If you're familiar with sockets, I would consider SocketServer.UDPServer (see http://docs.python.org/library/socketserver.html#socketserver-udpserver-example ). 如果您熟悉套接字,我会考虑使用SocketServer.UDPServer (请参阅http://docs.python.org/library/socketserver.html#socketserver-udpserver-example )。 UDP is definitely the simplest messaging system, but, obviously, you'll have to deal with fact that some messages can be lost, duplicated or delivered out of order. UDP绝对是最简单的消息传递系统,但显然,您必须处理某些消息可能丢失,重复或无序传递的事实。 If your protocol is very simple, it's relatively easy to handle. 如果您的协议非常简单,那么它的处理起来相对容易。 The advantage is you don't need any additional threads and no external dependencies are needed. 优点是您不需要任何其他线程,也不需要外部依赖项。 It also might be very good choice if you application doesn't have concept of session. 如果您的应用程序没有会话概念,它也可能是非常好的选择。

Might be good for a start, but there are much more details to be considered that are not included in your question. 一开始可能会有好处,但还有更多细节需要考虑,不包括在你的问题中。 I also wouldn't be worried of the fact, that sockets are not very Pythonic. 我也不会担心插座不是非常Pythonic的事实。 At the very end you're going to use sockets anyway, someone will just wrap them for you and you'll be forced to learn the framework, which in best case may be overwhelming for your requirements. 无论如何,你最终会使用套接字,有人会为你包装它们,你将被迫学习框架,在最好的情况下可能会满足你的要求。

(Please note my opinion is highly biased, as I love dealing with raw sockets.) (请注意我的观点非常偏颇,因为我喜欢处理原始套接字。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM