如何只在必要时从套接字读取数据

时间:2016-11-08 00:01:21

标签: python python-3.x sockets

我正在与一块硬件进行通信,该硬件只有一个支持基本API调用的基本API。

不幸的是,一些API调用违反了响应,有些则没有。我想在有一个时读取响应,或者在没有响应时不做任何操作。

以下是我一直在使用的代码:

def send_message(self, message, host):
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.connect((host, self.PORT))
        s.send(bytes(message, 'ascii'))
        data = s.recv(1024)
        print(data)

不幸的是,当没有收到数据时,这会绑定整个过程。我只想在有实际响应时读取数据。有没有办法用Python标准库做到这一点?

3 个答案:

答案 0 :(得分:2)

首先,如果您可以控制目标API,我建议为每条消息实施回复。对于发送的每条消息,回复ACK(确认)将使您的API更加健壮,并完全回避此问题。

如果那不是一个选项,那么我会为不同类型的消息创建类:

class Message(object):
    def __init__(self, msg):
        self.msg = msg

class MessageWReply(Message):
    await_reply = True

class MessageNoReply(Message):
    await_reply = False

创建所有邮件类,然后像这样使用它们:

def send_message(self, message, host):
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.connect((host, self.PORT))
        s.send(bytes(message, 'ascii'))

        if message.await_reply:
            data = s.recv(1024)
            print(data)

或者,如果您不想要创建所有类的开销,可以使用字典将消息映射到正确的操作:

messages = {
    'message with reply 1': True, # wait for reply
    'message with reply 2': True,
    'message with reply 2': True,
    'message without reply 1': False, # don't wait for reply
    'message without reply 2': False
}

然后这样做:

def send_message(self, message, host):
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.connect((host, self.PORT))
        s.send(bytes(message, 'ascii'))

        if messages[message]:
            data = s.recv(1024)
            print(data)

第二种方法具有更清晰的初始化(更少的样板代码),但有点不太明确。对于不熟悉代码的人,不清楚messages[message]存储的值实际意味着什么,而message.await_reply非常明确。像{{3}}这样的东西可能是一个很好的折衷方案 - 您可以在一个数据结构中初始化所有内容,同时为了清晰起见仍使用命名字段。

答案 1 :(得分:2)

如果您不知道响应是否应该先于发送消息,那么您注定要失败。让我再说一遍:如果API响应与否,你不知道什么时候它会结束游戏。那是因为问题“我应该等待回应吗?”是无法回答的。它完全与Python无关,切换语言无助于解决这个问题。但是这样的API会非常糟糕。许多有用的工具(例如超时,并发访问)是不可能(或非常难)实现的。

另一方面,如果您确实知道API应该何时响应,那么它就像创建两个函数一样简单:一个具有recv而另一个没有。并适当地使用它们。因此,您需要做的主要工作是区分通知(不需要响应)和请求(需要响应)。就是这样。

答案 2 :(得分:0)

我使用过类似的程序,在我使用if message的{​​{1}}中,message在这种情况下是从套接字接收的字符串。这是我的代码:

while True:
readbuffer = readbuffer + s.recv(1024)
temp = string.split(readbuffer, "\n")
readbuffer = temp.pop()

for line in temp:
    try:
        user = getUser(line)
        message = getMessage(line)
    except IndexError:
        print "Nothing to receive from the server!"

    if message:
        #responses here