1

マルチプレイヤーゲーム用の単純な netty サーバーを実装しています。私はNettyを理解しようとしています。

telnet経由でサーバーをテストします。私がしたことは、メッセージをすべてのチャネルにブロードキャストすることです。順調に稼働中です。また、閉じるイベントでマップからチャネルを削除しますが、これは問題ありません。

ただし、問題は、クライアントの 1 つが予期せず切断された場合です。コールバックが閉じられる前に、送信者がチャネルを切断した messageReceived コールバックが呼び出されます。

切断されたクライアントからのメッセージを適切に無視するにはどうすればよいですか? 私は使用StringBufferしますmessagedReceivedが、ケースStringBuffer.toStringも適切な文字列ではありません。最後に、切断されたチャネルは他のチャネルとそれ自体に無意味なメッセージをブロードキャストします。レシーバーチャネル自体が例外Connection reset by peer をスローする場合、チャネル自体は現在利用できないため、これは正常です。

コードは次のとおりです。

     @Override
     public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {

            System.out.println();
            System.out.println("------------------");


            Channel current = e.getChannel();
            System.out.println("SenderChannel:"+current.getId());

            if(!current.isOpen())
                System.out.println("Not Open");

            ChannelBuffer buf = (ChannelBuffer) e.getMessage();

            StringBuffer sbs = new StringBuffer();

            while(buf.readable()) {
                sbs.append((char) buf.readByte());
            }

            String s = sbs.toString();


            System.out.println(s);

            String you = "You:" + s;
            String other = "Other:" + s;



            byte [] uResponse = you.getBytes();
            byte [] otherResponse = other.getBytes();


            Iterator iterator = channelList.entrySet().iterator();
            while(iterator.hasNext()){
                  Map.Entry pairs = (Map.Entry)iterator.next();

                  Integer key = (Integer)pairs.getKey();
                  Channel c = (Channel)pairs.getValue();

                  System.out.println("ReceiverChannel:"+c.getId());

                  if(key != current.getId())
                      c.write(ChannelBuffers.wrappedBuffer(otherResponse));
                  else
                      c.write(ChannelBuffers.wrappedBuffer(uResponse));

            }

     }


    @Override
    public void channelDisconnected(ChannelHandlerContext ctx,
            ChannelStateEvent e){

        Channel ch = e.getChannel();


            channelList.remove(ch.getId());
            System.out.println();
            System.out.println("*****************");
            System.out.println("DisconnectEvent:"+ch.getId());
            System.out.println("*****************");
            System.out.println();
            ch.close();

    }
4

4 に答える 4

2

あなたが望む方法で問題を解決することはできません。ネットワークに問題がある場合、技術的には送信者はいつでも切断できます。

  • スレッドがmessageReceivedに入るとすぐに
  • channelListを反復処理している間
  • channelListを反復処理している間、ただし送信者にエコーバックした後
  • メッセージをブロードキャストした後

(パイプラインに順序付けされていない実行ハンドラーがない限り)イベントを発生させるスレッドで実行しているため、messageReceivedの処理中にNettyは切断されたイベントを発生させることができません。正しい解決策は、実際にはアプリケーションによって異なります。ブロードキャストの結果、他のすべての受信者が応答する場合は、接続されていないクライアント宛てのメッセージをサーバーに抑制させる方がよい/簡単です。

また、実際に文字列を使用する場合は、StringEncoder/StringDecoderを確認してください。メッセージイベントバッファに完全な文字列が含まれているという保証はコードにありません。

于 2013-02-01T15:06:36.730 に答える
1

これがマルチプレイヤー ゲーム サーバー用である場合は、Java ゲーム サーバーなどの既存の Netty ゲーム サーバー ソリューションを使用することをお勧めします。切断はセッションに送信されるイベントになり、イベント ドリブンであるため、独自のハンドラーを記述して、同じセッションでイベントをさらに受信するかどうかを決定できます。イベントは FIFO 順でキューに入れられるため、切断が発生した場合、後続のブロードキャストを進める必要はありません。

于 2013-02-01T07:59:17.267 に答える
1

各送信の周りに try/catch を配置するだけです。いずれかが失敗した場合は、対応するチャネルを閉じます。

于 2013-01-31T22:08:51.777 に答える
0

私は Java 開発者ではありません。ただし、ソケットの観点から見ると、このデータはバッファ内にあるか、ユーザーの切断前に送信されます。したがって、受信段階にあるとき、ユーザーはまだ接続されており、受信ユーザーの完了時に正確に切断されています。したがって、これを防ぐ最善の方法は、データを受信するたびにユーザーがまだ接続されているかどうかを確認することだと思います.

C# では、このコードを個人的に使用して、ユーザーがまだ接続されているかどうかを確認します。

if (client.Poll(0, SelectMode.SelectRead))
{
    byte[] checkConn = new byte[1];
    if (client.Receive(checkConn, SocketFlags.Peek) == 0)
        return false;
}
return true;

Java と Netty (および接続が TCP の場合) についてはわかりませんが、これは私が使用するものであり、Java に簡単に変換できる可能性があります。

于 2013-01-31T14:51:26.077 に答える