server.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. import socket
  2. import logging
  3. from traceback import format_exc
  4. from threading import Thread
  5. from websocket import WebSocket
  6. from exceptions import InvalidRequest
  7. from frame import CLOSE_NORMAL
  8. class Server(object):
  9. def __init__(self, port, address='', log_level=logging.INFO, protocols=[]):
  10. logging.basicConfig(level=log_level,
  11. format='%(asctime)s: %(levelname)s: %(message)s',
  12. datefmt='%H:%M:%S')
  13. self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  14. self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  15. logging.info('Starting server at %s:%d', address, port)
  16. self.sock.bind((address, port))
  17. self.sock.listen(5)
  18. self.clients = []
  19. self.protocols = protocols
  20. def run(self):
  21. while True:
  22. try:
  23. sock, address = self.sock.accept()
  24. client = Client(self, sock, address)
  25. client.server_handshake()
  26. self.clients.append(client)
  27. logging.info('Registered client %s', client)
  28. thread = Thread(target=client.receive_forever)
  29. thread.daemon = True
  30. thread.start()
  31. except InvalidRequest as e:
  32. logging.error('Invalid request: %s', e.message)
  33. except KeyboardInterrupt:
  34. logging.info('Received interrupt, stopping server...')
  35. break
  36. except Exception as e:
  37. logging.error(format_exc(e))
  38. self.quit_gracefully()
  39. def quit_gracefully(self):
  40. for client in self.clients:
  41. client.close(CLOSE_NORMAL)
  42. def remove_client(self, client, code, reason):
  43. self.clients.remove(client)
  44. self.onclose(client, code, reason)
  45. def onopen(self, client):
  46. logging.debug('Opened socket to %s' % client)
  47. def onmessage(self, client, message):
  48. logging.debug('Received %s from %s' % (message, client))
  49. def onping(self, client, payload):
  50. logging.debug('Sent ping "%s" to %s' % (payload, client))
  51. def onpong(self, client, payload):
  52. logging.debug('Received pong "%s" from %s' % (payload, client))
  53. def onclose(self, client, code, reason):
  54. msg = 'Closed socket to %s' % client
  55. if code is not None:
  56. msg += ' [%d]' % code
  57. if len(reason):
  58. msg += ' "%s"' % reason
  59. logging.debug(msg)
  60. class Client(WebSocket):
  61. def __init__(self, server, sock, address):
  62. super(Client, self).__init__(sock)
  63. self.server = server
  64. self.address = address
  65. self.send_lock = Lock()
  66. def onopen(self):
  67. self.server.onopen(self)
  68. def onmessage(self, message):
  69. self.server.onmessage(self, message)
  70. def onping(self, payload):
  71. self.server.onping(self, payload)
  72. def onpong(self, payload):
  73. self.server.onpong(self, payload)
  74. def onclose(self, code, reason):
  75. self.server.remove_client(self, code, reason)
  76. def onexception(self, e):
  77. logging.error(format_exc(e))
  78. def __str__(self):
  79. return '<Client at %s:%d>' % self.address
  80. if __name__ == '__main__':
  81. import sys
  82. port = int(sys.argv[1]) if len(sys.argv) > 1 else 80
  83. Server(port, log_level=logging.DEBUG).run()