2016-08-26 33 views
0

我在这里是一个noob,但试图设置一个脚本,我可以轮询一个套接字,并且当没有套接字数据发送时,循环继续运行并执行其他操作。我一直在玩使用select()发现的几个例子,但不管我如何组织代码,它似乎停止在server.recv()行上或附近,并等待响应。如果客户端没有发送数据,或者没有客户端连接,我想跳过这一点。Python套接字选择正在挂起 - 在等待套接字数据时执行其他任务?

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

实际应用是运行一个循环并为一些LED设置动画(需要根访问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次,然后就不再显示了。我不完全理解选择内部发生了什么,但我认为它只会打印一次。

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

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

任何帮助,非常感谢。

+0

服务器必须是它​​自己的循环imo – YOU

+0

感谢您的快速回复。我不知道我将如何实现这一点。你能分享一个示例代码片段吗?我是否将所有内容都封装在一个循环中?如果是,我会在哪里调用其他函数(那些将被反复调用的函数,仅在客户端发送传入数据时才会中断)? – kjav

+0

尝试使用超时(秒)调用'select.select()'选项:'select.select(input,[],[],1)'。 – acw1668

回答

0

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

简单相加的“0”超时到select.select()这样的:

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

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

每文档: “可选的超时参数指定超时以秒为一个浮点数当超时参数被忽略的功能块,直到至少一个文件描述符准备好。超时值零指定一个轮询并且永不阻塞。“

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