我想编写一个客户端可以连接到服务器并接收定期更新而无需轮询的服务器。我在使用 asyncore 时遇到的问题是,如果在调用 dispatcher.writable() 时没有返回 true,则必须等到 asyncore.loop 超时(默认为 30 秒)。
我尝试解决此问题的两种方法是 1) 将超时减少到较低的值或 2) 查询连接以了解下次更新的时间并生成足够的超时值。但是,如果您引用“man 2 select_tut”中的“Select Law”,它指出,“您应该始终尝试在没有超时的情况下使用 select()。”
有更好的方法吗?也许扭曲?我想尝试避免额外的线程。我将在此处包含变量超时示例:
#!/usr/bin/python
import time
import socket
import asyncore
# in seconds
UPDATE_PERIOD = 4.0
class Channel(asyncore.dispatcher):
def __init__(self, sock, sck_map):
asyncore.dispatcher.__init__(self, sock=sock, map=sck_map)
self.last_update = 0.0 # should update immediately
self.send_buf = ''
self.recv_buf = ''
def writable(self):
return len(self.send_buf) > 0
def handle_write(self):
nbytes = self.send(self.send_buf)
self.send_buf = self.send_buf[nbytes:]
def handle_read(self):
print 'read'
print 'recv:', self.recv(4096)
def handle_close(self):
print 'close'
self.close()
# added for variable timeout
def update(self):
if time.time() >= self.next_update():
self.send_buf += 'hello %f\n'%(time.time())
self.last_update = time.time()
def next_update(self):
return self.last_update + UPDATE_PERIOD
class Server(asyncore.dispatcher):
def __init__(self, port, sck_map):
asyncore.dispatcher.__init__(self, map=sck_map)
self.port = port
self.sck_map = sck_map
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.bind( ("", port))
self.listen(16)
print "listening on port", self.port
def handle_accept(self):
(conn, addr) = self.accept()
Channel(sock=conn, sck_map=self.sck_map)
# added for variable timeout
def update(self):
pass
def next_update(self):
return None
sck_map = {}
server = Server(9090, sck_map)
while True:
next_update = time.time() + 30.0
for c in sck_map.values():
c.update() # <-- fill write buffers
n = c.next_update()
#print 'n:',n
if n is not None:
next_update = min(next_update, n)
_timeout = max(0.1, next_update - time.time())
asyncore.loop(timeout=_timeout, count=1, map=sck_map)
最佳答案
“选择法则”不适用于您的情况,因为您不仅有客户端触发的(纯服务器)事件,还有时间触发的事件——这正是选择超时的目的。法律真正应该说的是“如果您指定超时,请确保在超时到来时您确实必须做一些有用的事情”。法律旨在防止忙等待;您的代码不会忙等待。
我不会将 _timeout 设置为最大值 0.1 和下一次更新时间,而是设置为最大值 0.0 和下一次超时。 IOW,如果在您进行更新时更新期已过,您应该立即进行该特定更新。
不必每次都询问每个 channel 是否要更新,您可以将所有 channel 存储在优先级队列中(按下一次更新时间排序),然后只对最早的 channel 运行更新(直到找到更新的 channel 时间未到)。您可以为此使用 heapq 模块。
您还可以通过不让每个 channel 都询问当前时间来节省一些系统调用,而是只轮询一次当前时间,然后将其传递给 .update。
关于Python 的 asyncore 使用可变超时定期发送数据。有没有更好的办法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1036646/