Python套接字选择是挂起的 - 在等待套接字数据时执行其他任务?

时间:2016-08-26 01:52:05

标签: python multithreading sockets select

我在这里是一个菜鸟,但是尝试设置一个我可以轮询套接字的脚本,当没有发送套接字数据时,循环继续运行并执行其他操作。我一直在使用select()找到的几个例子,但无论我如何组织代码,它似乎停在server.recv()行上或附近并等待响应。如果客户端没有发送数据,或者没有客户端连接,我想跳过这个。

请注意,如果此应用程序有任何不同,则此应用程序不需要服务器脚本发送任何回复数据。

实际应用程序是运行循环并为某些LED设置动画(需要root访问Raspberry Pi上的I / O)。我将通过套接字从另一个单独的脚本发送此脚本数据,这些套接字将传递动画的控制参数。这样,外部脚本不需要root访问权限。

到目前为止,数据的发送和接收效果很好,我只是无法在没有传入数据的情况下继续循环。我的理解是这是select()打算允许的,但我发现的例子似乎并没有那样工作。

我尝试添加server.setblocking(0)几个不同的地方无济于事。 (如果我理解正确的话,非阻塞实例应该允许代码跳过recv(),如果没有数据发送,但我可能会关闭这个。)

我的代码基于以下示例: http://ilab.cs.byu.edu/python/select/echoserver.html

这是服务器端脚本,后跟客户端脚本。

服务器代码:sockselectserver.py

#!/usr/bin/env python

import select
import socket
import sys

server = socket.socket()
host = socket.gethostname()
port = 20568
size = 1024
server.bind((host,port))
server.listen(5)
input = [server,sys.stdin]
running = 1
while running:
    inputready,outputready,exceptready = select.select(input,[],[])

    for s in inputready:

        if s == server:
            # handle the server socket
            client, address = server.accept()
            input.append(client)

        elif s == sys.stdin:
            # handle standard input
            junk = sys.stdin.readline()
            running = 0

        else:
            # handle all other sockets
            data = s.recv(size)
            if data:
                s.send(data)
            else:
                s.close()
                input.remove(s)
    print "looping"
server.close()

客户端代码:skclient.py

#!/usr/bin/python           # This is client.py file

import socket               # Import socket module

s = socket.socket()         # Create a socket object
host = socket.gethostname() # Get local machine name
port = 20568                # Reserve a port for your service.

s.connect((host, port))

data = "123:120:230:51:210:120:55:12:35:24"
s.send(data)
print s.recv(1024)
s.close                     # Close the socket when done

我希望通过这个例子看到“循环”永远重复,然后当客户端脚本发送数据时,看到数据打印,然后看到“循环”恢复打印一遍又一遍。那会告诉我它正在做我想从那里做的事情。

有趣的是,当我按原样测试时,每当我运行客户端时,我都会在屏幕上看到“循环”打印3次,然后不再显示。我不完全理解select中发生了什么,但我认为它只会打印一次。

我尝试将inputready .. select.select()移动到不同的地方,但发现每次都需要调用它,否则服务器会停止响应(例如,如果它在无尽的时间之前被调用一次:循环)。

我希望这可以变得简单,以便可以在制造商类中教授其他黑客类型,所以我希望我不需要对多线程和更复杂的解决方案太过疯狂。作为最后的手段,我正在考虑从外部脚本将所有参数记录到mySQL,然后使用此脚本从表中查询它们。我在那里有经验并且可能会工作,但似乎这个插座角度将是一个更直接的解决方案。

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

好消息。这是一个简单的修复,想要发布以防其他人需要它。上面的acw1668的建议让我走了。

简单地添加" 0"像这样的select.select():

inputready,outputready,exceptready = select.select(input,[],[],0)

这是在python文档中但不知何故我错过了它。点击此处:https://docs.python.org/2/library/select.html

根据文档: "可选的timeout参数指定超时为浮点数(以秒为单位)。省略timeout参数时,函数将阻塞,直到至少有一个文件描述符准备就绪。超时值为零指定轮询并且永不阻止。"

我测试了与上面相同的代码,在打印后立即使用time.sleep(5)添加了5秒的延迟"循环"线。随着延迟,如果没有数据或客户端,代码只是每5秒循环一次并打印"循环"到屏幕。如果我在5秒延迟期间启动客户端脚本,它会暂停,并在下一次5秒延迟结束时处理该消息。偶尔它不响应下一个循环,而是循环跟随。我假设这是因为第一次通过server.accept正在运行,下一次通过s.recv()正在运行实际交换数据。