server.py 3.7 KB

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