net-httpserver/webserver/asyncserver.py

111 lines
3.3 KiB
Python
Raw Normal View History

2015-03-01 21:52:24 +01:00
import socket, select
import os.path, mimetypes
class Server(object):
2015-04-03 00:52:40 +02:00
"""
Asynchronous server class. specify a client handler class and port in the constructor.
"""
2015-03-01 21:52:24 +01:00
def __init__(self, connection_class, port=8080):
self.port = port
self.connection_class = connection_class
self.listening_socket = socket.socket()
self.listening_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.listening_socket.bind(('127.0.0.1', port))
self.listening_socket.listen(5)
self.listening_socket.setblocking(0)
self.handlers = {self.listening_socket: self}
self.clients = []
def run(self):
2015-04-03 00:52:40 +02:00
"""
run the event loop
- collect sockets and min timeout
- do the select call and notify clients
"""
2015-03-01 21:52:24 +01:00
reads = [self.listening_socket] + [c.sock for c in self.clients]
writes = [c.sock for c in self.clients if c.should_write()]
others = [c.sock for c in self.clients]
2015-03-01 22:14:10 +01:00
try:
timeout = min([c.next_timeout() for c in self.clients])
except ValueError:
timeout = None
[rlist, wlist, xlist] = select.select(reads, writes, others, timeout)
2015-03-01 21:52:24 +01:00
for readable in rlist:
self.handlers[readable].do_read()
for writable in wlist:
self.handlers[writable].do_write()
for otherable in xlist:
self.handlers[otherable].do_other()
2015-03-01 22:14:10 +01:00
for c in self.clients:
c.try_timeout()
2015-03-01 21:52:24 +01:00
def do_read(self):
2015-04-03 00:52:40 +02:00
"""
do_read method on the server itself (it's also in the select).
accepts a connection.
"""
2015-03-01 21:52:24 +01:00
(sock, addrinfo) = self.listening_socket.accept()
c = self.connection_class(self, sock, addrinfo)
self.clients.append(c)
self.handlers[sock] = c
def client_closed(self, c):
2015-04-03 00:52:40 +02:00
"""
remove a client from the list and handlers
"""
2015-03-01 21:52:24 +01:00
self.clients.remove(c)
del self.handlers[c.sock]
2015-04-03 00:52:40 +02:00
# print "%d open connections" % len(self.clients)
2015-03-01 21:52:24 +01:00
def close(self):
2015-04-03 00:52:40 +02:00
""" close the server down and stop listening """
2015-03-01 21:52:24 +01:00
self.listening_socket.close()
class Client(object):
2015-04-03 00:52:40 +02:00
"""Client is the generic Server handler class. look at HTTPClient for more documentation"""
2015-03-01 21:52:24 +01:00
def __init__(self, parent, sock, addrinfo):
self.parent = parent
self.sock = sock
self.sock.setblocking(0)
self.addrinfo = addrinfo
self.write_buf = ""
self.read_buf = ""
self.to_close = False
#self.write("test")
# self.close()
def should_write(self):
return len(self.write_buf) > 0 or self.to_close
def do_read(self):
2015-04-03 00:52:40 +02:00
"""called by the event loop when the socket is readable"""
2015-03-01 21:52:24 +01:00
data = self.sock.recv(4096)
if not data: return self.close()
self.read_buf += data
self.on_data()
def do_write(self):
2015-04-03 00:52:40 +02:00
"""called by the event loop when the socket is writable"""
2015-03-01 21:52:24 +01:00
try:
if self.write_buf:
no_written = self.sock.send(self.write_buf)
self.write_buf = self.write_buf[no_written:]
if len(self.write_buf) == 0 and self.to_close:
self.sock.close()
self.parent.client_closed(self)
except socket.error:
self.on_error()
def on_data(self): raise NotImplementedError()
def do_other(self): pass
def on_error(self):
self.parent.client_closed(self)
2015-03-01 22:14:10 +01:00
def try_timeout(self): pass
def next_timeout(self):
return None
2015-03-01 21:52:24 +01:00
def write(self, msg):
self.write_buf += msg
def close(self):
self.to_close = True
class EchoClient(Client):
2015-04-03 00:52:40 +02:00
"""EchoClient is an example Client handler that implements an echo server"""
2015-03-01 21:52:24 +01:00
def __init__(self, parent, sock, addrinfo):
super(EchoClient, self).__init__(parent, sock, addrinfo)
def on_data(self):
self.write(self.read_buf)
self.read_buf = ""