【问题标题】:Python Sockets Select is hanging - Doing other tasks while waiting for socket data?Python Sockets Select 挂起 - 在等待套接字数据时执行其他任务?
【发布时间】:2017-01-02 14:11:16
【问题描述】:

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

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

实际应用程序是运行一个循环并为一些 LED 设置动画(这需要对 Raspberry Pi 上的 I/O 进行 root 访问)。我将通过将传递动画控制参数的套接字从另一个单独的脚本发送此脚本数据。这样外部脚本就不需要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 内部发生了什么,但我认为它只会打印 1 次。

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

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

非常感谢任何帮助。

【问题讨论】:

  • 服务器必须是自己的循环 imo
  • 感谢您的快速回复。我不确定我将如何实现这一点。你能分享一个示例代码片段吗?我是否会将所有内容都包装在一个循环中,如果是这样,我将在哪里调用我的其他函数(那些将被一遍又一遍地调用,仅在客户端发送传入数据时中断的函数)?
  • 尝试使用超时(以秒为单位)选项调用select.select()select.select(input,[],[],1)
  • 这可能会奏效 - 将在早上尝试。你能澄清一下这是如何工作的吗?我可能会将超时设置得很短——可能是 0.05 秒(这是否太短而无法工作?)——所以我可以很快回到动画灯光。例如,如果我的动画循环需要 1 秒(只是指出动画部分相当长,而 select.select() 相当短) - 如果客户端在此动画部分期间发送数据,当 select.select()没有运行,数据是否会被缓冲,然后在下次 select.select() 运行时可用并找到?

标签: python multithreading sockets select


【解决方案1】:

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

像这样在 select.select() 中简单地添加“0”超时:

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

这是在 python 文档中,但不知何故我错过了它。链接在这里:https://docs.python.org/2/library/select.html

根据文档:

可选的 timeout 参数将超时指定为以秒为单位的浮点数。当省略超时参数时,函数会阻塞,直到至少一个文件描述符准备好。超时值为零指定轮询并且从不阻塞。

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

【讨论】:

    猜你喜欢
    • 2016-09-19
    • 1970-01-01
    • 2023-04-01
    • 2012-09-10
    • 1970-01-01
    • 2013-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多