Форум сайта python.su
Ребята помогите победить.
Есть типовой сервер на asyncore. Всё работает замечательно, но засада в том, что никак не могу сделать, чтобы был какой-то таймер для таймаута.
Нужно, чтобы если от клиента не поступило данных в течение 30 секунд, его отключало и закрывало сокет.
import asyncore import socket class EchoHandler(asyncore.dispatcher_with_send): def handle_read(self): data = self.recv(8192) if data: print 'Received data = ', data self.send(data) def handle_error(self): print 'Error' def handle_close(self): print 'Client disconnected normal' class EchoServer(asyncore.dispatcher): def __init__(self, host, port): asyncore.dispatcher.__init__(self) self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.set_reuse_addr() self.bind((host, port)) self.listen(5) def handle_accept(self): pair = self.accept() if pair is not None: sock, addr = pair print 'Incoming connection from %s' % repr(addr) handler = EchoHandler(sock) server = EchoServer('localhost', 8080) asyncore.loop()
Офлайн
Насколько я понимаю, asyncore.dispatcher работает с сокетом в неблокирующем режиме, так что для сокета таймоут поставить не получится, придется делать самостоятельно. Я вот примерно набросал.
import asyncore import socket import time from collections import defaultdict class TimeoutController(object): TICK = 10.0 TIMEOUT = 30.0 def __init__(self): self.connections = defaultdict(float) def loop(self): while True: asyncore.loop(self.TICK, count=1) self.check_connections() def check_connections(self): now = time.time() for conn_id, (connection, last) in self.connections.items(): if now - last > self.TIMEOUT: print 'Close client by timeout' del self.connections[conn_id] connection.close() def checkin(self, connection): self.connections[id(connection)] = (connection, time.time()) class EchoHandler(asyncore.dispatcher_with_send): def __init__(self, controller, sock=None, map=None): self.controller = controller controller.checkin(self) asyncore.dispatcher_with_send.__init__(self, sock, map) def handle_read(self): data = self.recv(8192) self.controller.checkin(self) if data: print 'Received data = ', data self.send(data) def handle_error(self): print 'Error' def handle_close(self): print 'Client disconnected normal' self.close() class EchoServer(asyncore.dispatcher): def __init__(self, host, port, controller): asyncore.dispatcher.__init__(self) self.controller = controller self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.set_reuse_addr() self.bind((host, port)) self.listen(5) def handle_accept(self): pair = self.accept() if pair is not None: sock, addr = pair print 'Incoming connection from %s' % repr(addr) EchoHandler(self.controller, sock) controller = TimeoutController() server = EchoServer('localhost', 8080, controller) controller.loop()
Отредактировано PooH (Апрель 16, 2015 09:06:38)
Офлайн
PooH
ЗЫ: А зачем вы вообще эту рухлядь схватили?
Офлайн
NaganoEx
но есть же asyncio
Офлайн
sander
но есть же asyncio
Офлайн
PooH
Я вот примерно набросал.
Офлайн
PooH а подскажите пожалуйста, почему при connection.close() не вызывается событие def handle_close(self): ?
Офлайн
Какая-то засада, в случае если клиент отключается хорошо например через 5 сек. после подключения, то через 25 сек всё равно срабатывает таймер и снова закрывает сокет
Офлайн
NaganoExhandle_close вызывается когда соединение закрывают на другой стороне, заметьте я на это событие вызываю self.close() чтобы закрыть его со своей, посмотрите про двухфазное закрытие соединения в протоколе TCP хотя бы тут
почему при connection.close() не вызывается событие def handle_close(self): ?
Офлайн
NaganoExМой косяк. Набрасывал на коленке и не подумал об этом, надо у TimeoutController сделать примерно такой метод
Какая-то засада, в случае если клиент отключается хорошо например через 5 сек. после подключения, то через 25 сек всё равно срабатывает таймер и снова закрывает сокет
def checkout(self, connection): del self.connections[id(connection)]
Отредактировано PooH (Апрель 16, 2015 18:20:05)
Офлайн