Source code for net.server

import socket
import time
import Queue
from net.async import Async
from net.callback import Callback
from net.error import NetError, ServerError
from net.ip import Address
from net.protocol.util import get_protocol
from net import client

[docs]class Server(object): ''' Server connection handler. Serves as a basis for :class:`net.server.TCP` and :class:`net.server.UDP`. :param host: hostname or ip address :param port: port number or serivce name :param size: block read size :attribute async: :class:`net.async.Async` instance :callback onAccept(): Callback if the server accepts a new client :callback onListen(): Callback if the server starts accepting clients :callback onError(error): Callback if an error occurs ''' async = Async() def __init__(self, host, port, size=8192): # Setup instance self.address = Address((host, port)) self.size = size self.family = self.address.ip.family self.socket = None # Setup callbacks self.onAccept = Callback() self.onListen = Callback() self.onError = Callback() # Subscribe to callbacks self.onListen.bind(self._on_listen) def __eq__(self, other): ''' Compare this instance to an other instance or file descriptor. If the ``other`` argument is an integer, compare file descriptors. ''' if isinstance(other, Server): return id(other) == id(self) elif type(other) == int: if self.socket: return self.socket.fileno() == other else: return False def __enter__(self): ''' Convenience function for constructing a ``with`` statement:: >>> with Server('127.0.0.1', 6667, protocol='line') as echo: ... print echo ... echo.serve() ''' if not self.socket: self.listen() return self def __exit__(self, exc_type, exc_value, traceback): if isinstance(exc_type, KeyboardInterrupt): self.async.stop() return True elif isinstance(exc_type, socket.error): raise NetError(exc_value) else: return False def __repr__(self): return '<Server address=%r>' % (self.address,) def _on_listen(self): self.async.server(self, self._handle_accept, self._handle_error, ) def _handle_accept(self, address, remote): pass def _handle_error(self, exc_info): return exc_info def _prepare(self): return socket.socket(self.family, self.type)
[docs] def listen(self): ''' Start listening for client connections. ''' self.socket = self._prepare() try: self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) except socket.error: pass try: self.socket.bind(tuple(self.address)) self.socket.listen(1) except socket.error, e: raise ServerError(e) self.onListen.call()
def serve(self): while self.async.running: time.sleep(0.1)
class TCPBase(Server): type = socket.SOCK_STREAM
[docs]class TCP(TCPBase): ''' TCP server implementation:: >>> from net.async import start >>> from net.server import TCP >>> start(True) >>> with TCP('localhost', 2266, protocol='echo') as echo: ... for peer in echo: ... print 'New peer:', peer ... print >>peer, 'Welcome to the net echo server' ... Or using a more traditional Python syntax:: >>> server = TCP('localhost', 2266, protocol='echo') >>> server.listen() >>> for peer in server: ... print 'New peer:', peer ... peer.write('Welcome to the net echo server\\n') ... :param host: Server hostname or ip address :param port: Server port or service name :param size: Block read size :param protocol: Server protocolcol name or :class:`net.protocol.Protocol` instance :param args: Arguments for the server protocolcol class :param kwargs: Keyword arguments for the server protocol class ''' def __init__(self, host, port, protocol='line', *args, **kwargs): TCPBase.__init__(self, host, port) # Create protocol instance if type(protocol) in [str, unicode]: self.protocol = get_protocol('server', protocol) else: self.protocol = protocol # Setup callbacks self.onClientConnect = Callback() self.onClientDisconnect = Callback() def __iter__(self): ''' Yields new clients. ''' clients = Queue.Queue() def _on_accept(peer): clients.put(peer) # Register callback self.onAccept.bind(_on_accept) while self.async.running: try: yield clients.get(True, 0.1) except Queue.Empty: pass except KeyboardInterrupt: self.async.stop() # Unregister callbac self.onAccept.remove(_on_accept) def __repr__(self): return '<TCP Server address=%r protocol=%r>' % (self.address, self.protocol) def _handle_accept(self, remote, address): peer = client.TCP(address[0], address[1], remote=remote, protocol=self.protocol) peer.onConnect.addCallback(self._on_peer_connect, peer=peer) peer.onDisconnect.addCallback(self._on_peer_disconnect, peer=peer) # Tell the async core we have a connection peer.onConnect.call() # Let the callbacks know we have accepted a client self.onAccept.call(peer) return address, remote def _on_peer_connect(self, peer=None): self.onClientConnect.call(peer) def _on_peer_disconnect(self, peer=None): self.onClientDisconnect.call(peer)