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

Python 如何仅在必要时从套接字读取数据,python,python-3.x,sockets,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.sen

我正在与一个只有基本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标准库做到这一点?

我使用过类似的程序,在其中一个程序中,我使用了
if message
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

我使用过类似的程序,在其中一个程序中,我使用了
if message
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

首先,如果您可以控制目标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\u reply
则非常清楚。类似这样的做法可能是一个很好的折衷方案—您可以在一个数据结构中初始化所有内容,同时仍然使用命名字段以保持清晰。

首先,如果您可以控制目标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\u reply
则非常清楚。类似这样的做法可能是一个很好的折衷方案-您可以在一个数据结构中初始化所有内容,同时仍然使用命名字段以保持清晰性。

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


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

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


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

可能取决于您的操作系统,但可能
select
模块适合您?可能取决于您的操作系统,但可能
select
模块适合您?