Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to send data to a different request from the current request handler? (Python SocketServer with ThreadingMixIn)
    text
    copied!<p>I'm writing a multiplayer game server and client in Python, using the built-in SocketServer's TCPServer and ThreadingMixIn because it seems easier than manually managing the socket and threading modules. (I'd like to stick with the built-in modules for this.) It uses a protocol similar to HTTP for communication (GTP).</p> <p>Requests involving only one client already work. If a client sends the request "<code>GET /index.html GTP/0.2</code>", the server just has to respond "<code>GTP/0.2 200 OK</code>" to that client. But if a game is going on between clients A and B (as recorded in the server's state) and client A sends the request "<code>TURN &lt;my turn info&gt; GTP/0.2</code>", then after taking player A's turn, how does the server notify <em>both</em> players A and B of the changes?</p> <p>Here are the essentials of my code so far:</p> <pre><code>import SocketServer import socket, threading # not yet used class ThreadingGameServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): def __init__(self, server_address, RequestHandlerClass): SocketServer.TCPServer.__init__(self, server_address, RequestHandlerClass) self.players = [] self.games = [] class GameRequestHandler(SocketServer.BaseRequestHandler): def setup(self): self.request_data = None self.response_data = None def handle(self): while True: self.request_data = self.request.recv(4096) if not self.request_data: break # Client disconnected # delegate handling to do_GET, do_POST, etc do_method = 'do_' + self.request_data.split()[0] if not hasattr(self, do_method): self.request.sendall("GTP/0.2 501 Not Implemented\r\n\r\n") continue try: do = getattr(self, do_method) do() except Exception as e: break def do_GET(self): body = '&lt;contents of {}&gt;'.format(self.my_request.param) data = "GTP/0.2 200 OK\r\nContent-Length: {}\r\n\r\n{}".format(len(body), body) self.request.sendall(data) def do_LOGIN(self): """ Create a player with the requested username and this handler. Add the player to self.server.players. Respond with 200 OK, body "Welcome!, &lt;username&gt;". """ def do_PLAY(self): """ If the requested opponent is not logged in and ready to play, respond with 403 Forbidden. Create a game with this player and the requested opponent. Remove the two players from self.server.players. Add the game to self.server.games. Respond with 200 OK, body "Begin game with &lt;opponent&gt;". How do I send "Begin game with &lt;this player&gt;" to the opponent as well? """ def do_TURN(self): """ If it is not this player's turn, respond with 403 Forbidden. Modify the game's state in self.server.games, including making it be the opponent's turn. Respond with 200 OK, body "&lt;new game state&gt;". How do I send the response to the opponent as well? """ def do_EXIT(self): """ If this player is logged in, log them out. If they are in a game, respond to their opponent with 200 OK, body "Game over" (how?). End their request handler. """ class GameClient(object): def __init__(self, server_address): self.socket = socket.create_connection(server_address) def run(self): """ Read user input, e.g. "&gt; login foobar". Send request to server, e.g. self.socket.sendall("LOGIN foobar GTP/0.2\r\n\r\n") Get server's reply via self.socket.recv(4096) Print the reply body, e.g. "Welcome, foobar!" """ # On the server machine server = ThreadingGameServer((socket.gethostname(), 4242), GameRequestHandler) server.serve_forever() # On each client machine client = GameClient(('server.mygame.com', 4242)) client.run() </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload