采用Python实现的异步TCP服务器

jopen 11年前

这是一个采用Python编写的非常基本的异步套接字socket服务器。

import socket  import select      class Client(object):      def __init__(self, addr, sock):          self._socket = sock          self._backlog = b''          self.done = False        def read(self, data):          """          This function is meant to be overloaded by classes          inheriting from Client. It's executed whenever something          is received from the client.          """          ss = data.decode('utf-8', 'replace')          for s in ss.strip().split('\n'):              if s == "hello":                  self.write("Hello, World!\n")        def write(self, data):          self._backlog += bytearray(data, 'utf-8')        def _read_ready(self):          """          Since sockets only allow for reading a specified amount          of bytes we can set the socket to not block on empty          recv and continue receiving until the call fails. There          by receiving more than the specified amount.          """          data = b''          self._socket.setblocking(False)          while True:              try:                  r = self._socket.recv(100)                  data += r              except (socket.timeout, socket.error):                  break          self._socket.setblocking(True)          if not r:              self.done = True              return          self.read(data)        def _write_ready(self):          """          We only write things to the socket when it signals that          it's ready to receive something. Not doing this an          relying on implicit buffers works most of the time but          this really isn't a difficult thing to implement.          """          if self._backlog:              count = self._socket.send(self._backlog)              self._backlog = self._backlog[count:]      def main_loop():      sock = socket.socket()      sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)      sock.bind(("", 8002))      sock.listen(1)  # listen(1) means that we only allow new                      # connections when the previous ones have                      # been properly processed.      clients = {}  # Keep a dictionary mapping sockets to clients      try:          while True:              # We add `sock` to the `rlist` since it will signal              # that it's ready to be read when a new connection is              # waiting to be accepted.              rlist = [sock] + list(clients.keys())              wlist = [s for (s, c) in clients.items() if c._backlog]              (rs, ws, _) = select.select(rlist, wlist, [])              try:                  for r in rs:                      if r == sock:                          (s, addr) = sock.accept()                          clients[s] = Client(addr, s)                      elif r in clients:                          clients[r]._read_ready()                  for w in ws:                      if w in clients:                          clients[w]._write_ready()              except Exception:                  # Including this catch as an example. It's often                  # nice to handle this and then break from the loop.                  raise              # Iterate over all the clients to find out which ones              # the client has disconnected from so we can remove              # their references and let them be collected.              for s in list(clients.keys())[:]:                  if clients[s].done:                      del clients[s]              sock.listen(1)      except KeyboardInterrupt:          print("Got CTRL-C, quitting")      finally:          sock.close()