2012-11-03 22 views
3

我正在使用內置的SocketServer的TCPServer和ThreadingMixIn編寫多人遊戲服務器和客戶端,因爲它比手動管理套接字和線程模塊更容易。 (我想堅持使用內置模塊)。它使用類似於HTTP進行通信的協議(GTP)。如何將數據發送到當前請求處理程序的不同請求? (使用ThreadingMixIn的Python SocketServer)

只涉及一個客戶端的請求已經工作。如果客戶端發送請求「GET /index.html GTP/0.2」,則服務器只需向該客戶端迴應「GTP/0.2 200 OK」。但是如果客戶端A和B之間正在進行遊戲(記錄在服務器的狀態),並且客戶端A發送請求「TURN <my turn info> GTP/0.2」,那麼在玩家A輪流之後,服務器如何通知兩個玩家A和B變化?

這裏是我的代碼的要領至今:

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 = '<contents of {}>'.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!, <username>". 
     """ 

    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 <opponent>". 
     How do I send "Begin game with <this player>" 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 "<new game state>". 
     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. "> 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() 

回答

1

有可能是一個更好的方式來做到這一點,但我很久以前設計我自己的方法(回來時,我是新的使用Python!)爲每個客戶提供一種收件箱。每個客戶端會定期向服務器詢問其收件箱中的內容,並相應地解析這些命令。

我會密切關注這個問題,我很想看到比我更好的方法。我也建議在嘗試之前等待答案。

+0

我正在爲C++編寫類似的東西。這個想法是爲每個客戶**僅** **收件箱。收件箱是一個線程安全隊列,並且客戶端在出列操作上阻塞。 – Omnifarious

+0

這就是我最終做的。客戶端每秒向服務器發送PING請求,並且如果他們的收件箱中有任何新消息,那麼這些請求會發送響應PING。 – Remy

相關問題