run_server.py 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import threading
  2. import socket
  3. import sys
  4. import io
  5. import collections
  6. BUFFER_SIZE = 1024
  7. if __name__ == "__main__":
  8. port = int(sys.argv[1])
  9. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  10. # Thread-safe bidirectional one-to-many mapping between room number and client socket
  11. class RoomMapping:
  12. def __init__(self):
  13. self.client2room = {}
  14. self.room2clients = collections.defaultdict(set)
  15. self.lock = threading.Lock()
  16. def join(self, client, room):
  17. with self.lock:
  18. self.room2clients[room].add(client)
  19. self.client2room[client] = room
  20. def leave(self, client):
  21. with self.lock:
  22. room = self.client2room[client]
  23. self.room2clients[room].remove(client)
  24. del self.client2room[client]
  25. def get_clients_in_same_room(self, client):
  26. with self.lock:
  27. room = self.client2room[client]
  28. return list(self.room2clients[room])
  29. mapping = RoomMapping()
  30. def send_line(conn, msg):
  31. conn.send((msg+"\n").encode('utf-8'))
  32. def client_thread(conn, address):
  33. with conn:
  34. file = conn.makefile();
  35. for line in file:
  36. if line.startswith("POLL"):
  37. send_line(conn, "ALIVE")
  38. elif line.startswith("JOIN"):
  39. print("JOIN EVENT SERVER " + line)
  40. room_number = int(line[5:])
  41. mapping.join(conn, room_number)
  42. send_line(conn, "ACK JOIN " + str(room_number))
  43. # print("joined...", mapping.client2room)
  44. elif line.startswith("LEAVE"):
  45. mapping.leave(conn)
  46. send_line(conn, "ACK LEAVE")
  47. # print("left...", mapping.client2room)
  48. elif line.startswith("MSG"):
  49. # print("got MSG: ", line)
  50. conns = mapping.get_clients_in_same_room(conn)
  51. for c in conns:
  52. if c is not conn:
  53. send_line(c, line)
  54. else:
  55. print("Received line does not match protocol: ", line)
  56. print("Closed client connection: %s:%s" % address)
  57. with s:
  58. s.bind(("localhost", port))
  59. s.listen(5)
  60. print("Accepting client connections.")
  61. while True:
  62. conn, address = s.accept()
  63. print("Accepted client connection: %s:%s" % address)
  64. t = threading.Thread(target=client_thread, args=(conn,address))
  65. t.daemon = True
  66. t.start()