我想编写一个服务器,客户端可以连接到该服务器并接收定期更新,而无需轮询。我在asyncore中遇到的问题是,如果在调用dispatcher.writable()时不返回true,则必须等到asyncore.loop超时后(默认值为30s)。
我试图解决这一问题的两种方法是:1)将超时时间减少到一个较低的值,或2)查询连接,以便它们下次更新时生成足够的超时值。但是,如果您在“man 2 Select tut”中提到“Select Law”,它会指出,“您应该始终尝试在没有超时的情况下使用Select()。”
有更好的办法吗?也许扭曲了?我想尽量避免额外的线程。我将在这里包括变量timeout示例:
#!/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)
“选择法则”不适用于您的案例,因为您不仅有客户端触发的(纯服务器)活动,还有时间触发的活动-这正是选择超时的作用。法律应该说的是“如果你指定了一个超时,那么当超时到来的时候,你必须做一些有用的事情”。法律是为了防止忙着等待;你的代码不是忙着等待。
我不会将超时设置为最大值0.1和下一次更新时间,而是设置为最大值0.0和下一次超时。听着,如果你在做更新时更新期已经过期,你应该马上做那个特定的更新。
您可以将所有通道存储在优先级队列中(按下次更新时间排序),然后只对最早的通道运行更新(直到找到更新时间尚未到达的通道),而不是每次都询问每个通道是否要更新。你可以使用heapq模块。
您还可以通过不让每个通道请求当前时间来保存一些系统调用,而只轮询当前时间一次,并将其传递给.update。
也许你可以用
sched.scheduler
来完成,就像这样(n.b.未测试):这基本上是德米尔古斯的解决方案,粗糙的边缘变成圆形。它保留了他的基本思想,但防止了运行时错误和繁忙的循环,并经过了测试。[编辑:解决了在延迟期间修改计划程序的问题]
相关问题 更多 >
编程相关推荐