1

2 つのスレッドを持つアプリケーションがあります。そのネットワーク制御ゲーム、

1. スレッド (サーバー)

  • ソケット接続を受け入れてメッセージを受信する
  • メッセージが送信されたら、イベントを作成してキューに追加します

コード:

class SingleTCPHandler(SocketServer.StreamRequestHandler):
    def handle(self):
        try:
            while True:
                sleep(0.06)
                message = self.rfile.readline().strip()              
                my_event = pygame.event.Event(USEREVENT, {'control':message})
                print message
                pygame.event.post(my_event)

2. スレッド (pygame)

  • ゲーム演出担当
  • サーバーが入力するイベントキューを介してメッセージを受信します
  • 60ms ごとのメッセージに基づいてゲームをレンダリングします

これがゲームの外観です。制御メッセージは、小さな正方形の速度です。

ここに画像の説明を入力

デバッグの目的で、次を使用して仮想マシンからサーバーに接続します。

ncat 192.168.56.1 2000

そして、制御メッセージを送信します。本番環境では、これらのメッセージは Android デバイスによって 50 ミリ秒ごとに送信されます。

問題

私のデバッグ環境では、数秒間隔でメッセージを手動で入力します。その間、ゲームは何度もレンダリングされます。何が起こるかというと、message(サーバー コード内の) は以前に受信した値で常にレンダリングされます。

以下を送ります。

1:0.5

アプリが開始されたコンソールで、print messageサーバーコードの行により次のメッセージが表示されます。

alan@alan ~/.../py $ python main.py 
1:0.5

ゲームが行うことは、この値を常に (レンダリングする期間で、数秒ごとに入力するのではなく) 受け取るように動作することです。

print messageそれが起こっているので、これwhile Trueも常に出力され、出力は次のようになると予想されます。

alan@alan ~/.../py $ python main.py 
1:0.5
1:0.5
1:0.5
1:0.5
....

しかし、そうではありません。アドバイスしてください(説明が不十分な場合は、件名を何に変更するかについての提案も受け付けています)

4

1 に答える 1

4

ループwhile Trueはソケットをポーリングしています。これは、メッセージが送信されたときにのみメッセージを取得します。ダウンストリームのイベント コンシューマーがこれらのメッセージで何をしているのかはわかりません。.6 秒ごとにイベントをディスパッチし、ソケット キューの次のレコードの内容を出力するだけです。ゲームがレンダリング ループごとに現在のコマンドを出力するようにするprintには、ソケット ポーラーではなく、レンダリング ループ自体にステートメントを配置する必要があります。また、最後のコマンドを「スティック」にして、ユーザーが実際に何かを入力しない限り新しいイベントを投稿したくないように見えるので、if message:ここにあるソケット ハンドラのイベント ディスパッチ コードをブロックします。現時点では、最後にチェックしてからユーザーが何も入力しなかった場合、0.6 秒ごとに空のイベントを送信します。

sleepまた、ソケットハンドラーに a 、またはそのために持っているループを入れることはおそらく賢明ではないと思います。のSocketServerソケットでデータを受信するたびにそれを呼び出すので、ループが効果的に実行されます。ここでそれを行うと、バッファのオーバーフローが発生する可能性があると思います。pygame にイベントを投稿する頻度を制御したい場合は、特定のタイプのイベントが既にキューに入れられている場合に追加されるのをブロックするか、キューから特定のタイプのすべてのイベントを取得することによって、おそらくそれを行いたいと思うでしょう。ゲーム ループが発生し、最初または最後のもの以外はすべて無視されます。最後のイベントがポストされてから一定の時間が経過しているかどうかをハンドラーにチェックインすることで制御することもできますが、イベント コンシューマーが、複数のイベントが待機しているイベント キューを処理できることを確認する必要があります。必要に応じて適切なキューのフラッシュを行います。

編集:

ドキュメント:

違いは、2 番目のハンドラーの readline() 呼び出しは改行文字に遭遇するまで recv() を複数回呼び出すのに対し、最初のハンドラーの単一の recv() 呼び出しはクライアントから送信されたものを 1 回で返すことです。 sendall() 呼び出し。

そうです、行全体を読むことが保証されています。try実際、処理する入力がない限りこれは呼び出されないため、これも必要ではないと思います。

于 2013-01-14T17:16:03.547 に答える