Ich wollte einen Server schreiben, zu dem ein Client eine Verbindung herstellen und regelmäßige Updates ohne Polling erhalten konnte. Das Problem, das ich mit Asyncore hatte, ist, dass Sie, wenn Sie keinen true-Wert zurückgeben, wenn dispatcher.writable() aufgerufen wird, warten müssen, bis der Asyncore-Loop abgelaufen ist (Standardwert ist 30s).
Die beiden Möglichkeiten, die ich versucht habe, dieses Problem zu umgehen, sind 1) die Timeout-Zeit auf einen niedrigen Wert zu reduzieren oder 2) Verbindungen abzufragen, wann sie als nächstes aktualisiert werden, und einen angemessenen Timeout-Wert zu generieren. Wenn Sie sich jedoch auf das 'Select Law' in 'man 2 select_tut' beziehen, heißt es: "Sie sollten immer versuchen, select() ohne Timeout zu verwenden."
Gibt es einen besseren Weg, dies zu tun? Vielleicht Twisted? Ich wollte versuchen, zusätzliche Threads zu vermeiden. Ich werde hier das Beispiel mit variablem Timeout einbeziehen:
#!/usr/bin/python
import time
import socket
import asyncore
# in Sekunden
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 # sollte sofort aktualisiert werden
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 'lesen'
print 'empfangen:', self.recv(4096)
def handle_close(self):
print 'schließen'
self.close()
# für variable Timeout hinzugefügt
def update(self):
if time.time() >= self.next_update():
self.send_buf += 'hallo %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 "hören auf Port", self.port
def handle_accept(self):
(conn, addr) = self.accept()
Channel(sock=conn, sck_map=self.sck_map)
# für variable Timeout hinzugefügt
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() # <-- Schreibpuffer füllen
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)