Python:非阻塞套接字或异步I/O

11

我是Python的新手,目前需要编写一个Python套接字脚本,与设备(气象站)通过TCP/IP通信。
设备充当服务器端(监听IP:PORT,接受连接,接收请求,传输数据)。
我只需要发送一条消息,接收答案,然后平稳地关闭和关闭套接字。

try:
    comSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error, msg:
    sys.stderr.write("[ERROR] %s\n" % msg[1])
    sys.exit(1)

try:
   comSocket.connect((''))
except socket.error, msg:
   sys.stderr.write("[ERROR] %s\n" % msg[1])
   sys.exit(2)

comSocket.send('\r')
comSocket.recv(128)
comSocket.send('\r')
comSocket.recv(128)
comSocket.send('\r\r')
comSocket.recv(128)

comSocket.send('1I\r\r3I\r\r4I\r\r13I\r\r5I\r\r8I\r\r7I\r\r9I\r\r')

rawData = comSocket.recv(512)

comSocket.shutdown(1)
comSocket.close()

我的问题是:
通信通道不稳定,设备响应速度慢。因此,有时设备只会回复长度为0的消息(只是一个确认),我的代码会被冻结并永远等待响应。
这段代码包含了涉及SOCKET部分的内容,整个代码将在CRON下运行,所以冻结不是期望的行为。

我的问题是:
在Python中,如何处理这种情况最好,使得代码不会冻结并永远等待响应,而是尝试继续进行下一个发送(或类似操作)。


5
你应该看看 Python 的 Twisted 库。它是一个异步网络框架,可以让这个过程更加容易。 - Andrea
使用Twisted库可能会起作用,但为了一个消息而使用整个库似乎有些过度杀鸡。也许您需要让CRON打开一个子进程,在单独的线程中进行套接字通信。这样,您就可以避免阻塞问题。 - chisaipete
@Andrea,因为我有类似的问题要问。Twisted不是为服务器端设计的吗?如何修改它以在客户端使用? - Hangon
@Hangon,这些场景本质上并没有什么不同,两者都是CLI Python。 - Andrea
3个回答

11
你可以尝试使用超时方法,例如Russel代码,或者你可以使用非阻塞socket,就像下面的代码所示。它永远不会在 socket.recv 处被阻塞,你可以在循环中使用它重试任意次数。这样,你的程序就不会因为超时而挂起。通过这种方式,你可以测试数据是否可用,如果不可用,你可以做其他事情并稍后再试。
socket.setblocking(0)
while (retry_condition):
    try:
        data = socket.recv(512)
    except socket.error:
        '''no data yet..'''

3
我建议使用eventlet和green线程来完成这个任务。
Twisted是一个不错的库,但对于这样一个简单的用例来说,学习曲线有点陡峭。
在这里查看一些示例here

1

在接收之前,尝试在socket上设置超时:

comSocket.settimeout(5.0)
try:
    rawData = comSocket.recv(512)
except socket.timeout:
    print "No response from server"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接