1

私は Python でゲーム サーバーを作成し、Faucet Networking プラグインを使用して Game Maker でゲーム クライアントを作成しています (それは問題ではありません)。クライアントはプレーヤーが移動するたびにサーバーに UPDATEXY メッセージを送信し、クライアントにはメッセージのチャットがあります。2 つのクライアントがサーバーに接続されていると、クライアントがメッセージで過負荷になっているように見えます (ランタイムがさらに進むと、チャット メッセージの表示が遅くなり、プレイヤーは実際の他のプレイヤーよりも遅れます)。これは、クライアントがメッセージが流れている速度でメッセージを処理できないためだと思われるため、すべてのメッセージを受信バッファーにダンプして無視する機能をクライアントに実装しました。これは機能しているように見えましたが、プレイヤーは激しく動き回っていました。この問題に対する何らかの「完全な修正」はありますか?

ちなみにプロトコルはTCPです。これは TCP 自体の問題ですか、それとも間違った使い方をしているだけですか? UDP への切り替えは役に立ちますか?

ありがとう。

編集:コードが要求されたので、ここでサーバーに行きます:

def sendmsg(msgtype, msg, conn, args=None):
    if msgtype == MSG_PLAYER_ASSIGN_ID:
        dataload = struct.pack('!hhh', MSG_STARTBYTE, msgtype, msg)
        conn.send(dataload)

    elif msgtype == MSG_PLAYER_UPDATEXY: #This will only ever be broadcasted
        #print("Sending xy from " + str(args['pid']))
        dataload = struct.pack('!hhhhh', MSG_STARTBYTE, msgtype, args['pid'], msg[0], msg[1])
        conn.send(dataload)

    elif msgtype == MSG_ASKFORLIST:
        players = msg
        for player in players:
            if args['pid'] != player.pid and player.dead == False:
                dataload = struct.pack('!hhhh' + str(len(str(player.name))) + "s", MSG_STARTBYTE, MSG_PLAYERENTRY, player.pid, len(str(player.name)), player.name.encode())
                conn.send(dataload)
                loginfo("Sent a player")

^これはほんの一部のパケットです。他にもありますが、それらはすべてそれらとほとんど同じです

ここでクライアントに行きます:

if msgtype == MSG_PLAYER_UPDATEXY
{
if tcp_receive(serversocket, 6){
pidtoupdate = read_short(serversocket)
//show_message(string(pidtoupdate))
if objNewNetProcessor.pid != pidtoupdate
{
xtoupdate = read_short(serversocket)
ytoupdate = read_short(serversocket)
playertoupdate = ds_map_find_value(global.players, string(pidtoupdate))
if playertoupdate != objChar
{
playertoupdate.y = ytoupdate
playertoupdate.x = xtoupdate}
}}}

if msgtype == MSG_CHAT
{
if tcp_receive(serversocket, 4){
fromperson = read_short(objNewNetProcessor.serversocket)
strlen = read_short(objNewNetProcessor.serversocket)
tcp_receive(objNewNetProcessor.serversocket, strlen)
chatmsg = read_string(objNewNetProcessor.serversocket, strlen)
display_chat(fromperson, chatmsg)
}}

^申し訳ありませんが、これは完全に混乱したものです。これは今のところ一時的なコードです。それもほんの数パケットで、そのコードの下でより多くを処理しますが、それらはすべてそれらに似ています。

4

2 に答える 2

1

通常、これは問題なく動作するはずです。これは CPU 負荷が高い場合の問題ではないかと思います。1 秒あたり 60 回の更新はかなりの量ですが、接続されているクライアントが 2 つだけの場合、処理するトラフィックはそれほど多くないはずです。比較のために、Gang Garrison 2 は毎秒 30 の更新しか使用しませんが、適切な PC を使用すると、サーバーで 20 人のプレイヤーを問題なく処理できます。タスク マネージャーでクライアントとサーバーの CPU 負荷を確認して安全を確保してください。ただし、それが問題になるとは思いません。

クライアントの「バックログ」をクリアすることで追いつくことができる場合、これはおそらくネットワーク速度やサーバーの問題ではありませんが、Wiresharkを使用してクライアントのトラフィックをログに記録し、すべてが予想されます (たとえば、パケットは予想されるレートで送受信され、均等なタイミングで送信されます)。

クライアントにバックログが蓄積しているように見えるので、クライアントは各ステップでできるだけ多くのメッセージを消費しようとしますか、それとも 1 つのサーバー ステップのメッセージだけを消費しようとしますか? クライアントステップごとに1つのサーバーステップのみを処理する場合、必然的に発生する接続の問題により、永久に遅れが生じます。これは、説明したことと一致しているようです.

Russell Borogove も良い指針を示してくれました。サーバー上の各ゲーム関連ソケットで Nagle のアルゴリズムが無効になっている (=tcp_nodelay が有効になっている) ことを確認してください。Faucet はデフォルトでこれを行います。

于 2012-05-20T10:25:49.910 に答える
1

通常、TCP は、適切なサイズのデータ​​ チャンク (100 から 1000 バイトのオーダー) をまだ送信する準備ができていない場合、何かを送信する前に最大約 200 ミリ秒待機するように構成されています。これは Nagle アルゴリズムと呼ばれます。クライアントが 60 fps (~16 ミリ秒周期) で更新を送信しようとすると、多くの古いデータがバーストすることになります。

Nagle バッファリングをオフにすることは可能ですが、UDP はリアルタイム ゲームでの一定の位置更新などに適しています。

とは言っても、かなり高速なマシン上の Python サーバーが 2 つのクライアント分の更新に対応できることを期待しているので、何か他のことが起こっている可能性があります。

于 2012-05-15T22:04:55.270 に答える