0

ClientBootStrapについて質問があります。これがシナリオです。

  1. Client_XはServer_Aに参加したいと考えています。
  2. しかし、Server_AはどういうわけかClient_xがServer_Bに参加することを望んでいます。
  3. したがって、Server_AはServer_Bの情報を再接続のためにClient_Xに送信します
  4. Client_XはRECONNECTIONメッセージを受け取るとすぐに、Server_Aからの切断を試み、Server_Bへの接続を試みます。しかし、それは失敗します。クライアントがServer_Aから切断するとすぐに、切断されたチャネルを使用できなくなるためです。

これは単純に見えます。しかし、これが私の実装です

    @Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)throws Exception  {
    if(e.getMessage() instanceof SomePacket){
    ....
    }else if(e.getMessage() instanceof Reconnect){ //Server_A has sent a RECONNECT Message.(Redirection)
        Reconnect theReconnectPacket = (Reconnect)e.getMessage();
        String hostname = theReconnectPacket.getHostname();
        int port = theReconnectPacket.getPort();

        this.reconnectHost  = hostname;
    this.reconnectPort  = port;
    this.currentState   = 1;

    ctx.getChannel().disconnect();    //DISCONNECT FROM SERVER_A

     }
}

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

     if(this.currentState == 1){

        Channel disconnectedChannel = ctx.getChannel();

    if (!disconnectedChannel.isConnected()){

    SocketAddress destinationAddress = new InetSocketAddress(this.reconnectHost, this.reconnectPort);
           //TRYING TO RECONNECT SERVER_B
    disconnectedChannel.connect(destinationAddress);    //**Error Line:java.nio.channels.ClosedChannelException**

    }

      }


    super.channelDisconnected(ctx, e);
}

エラー行でわかるように、この例外が発生しました:java.nio.channels.ClosedChannelException。切断した後、同じチャンネルを使用できませんでしたか?切断されたら、完了しますか?SimpleChannelHandlerで接続を再作成するにはどうすればよいですか?

さらなるコメントをありがとう:)

<<<<<新しいアプローチ>>>>>>

Ok。そのため、SimpleChannledHandlerでは、ClientBootStrapを使用して別のポートに接続します。

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

       Channel disconnectedChannel = ctx.getChannel();
    final ClientDataObject oldObject = ClientDataState.clientObject.get(disconnectedChannel);

    if(oldObject.getClientState() == 1){

        if (!disconnectedChannel.isConnected()){

SocketAddress destinationAddress = new InetSocketAddress(this.reconnectHost, this.reconnectPort);

ChannelFuture connectFuture = bootstrap.connect(destinationAddress);

connectFuture.addListener(new ChannelFutureListener() {
    @Override
    public void operationComplete(ChannelFuture channelFuture) throws Exception {

        Channel newChannel = channelFuture.getChannel();
    ClientDataObject newObject =  ClientDataState.clientObject.get(newChannel);
                      newObject.setClientID(oldObject.getClientID());


                     newObject.setClientState(oldObject.getClientState());
                    newObject.setRoomId(oldObject.getRoomId());
                    newObject.setClientState(1);

                    ClientDataState.clientObject.set(newChannel, newObject);

                    Channels.write(newChannel, new Login(newObject.getClientID()));
               }});             

        }else{
                     //Channled connected
            }

    }

    super.channelDisconnected(ctx, e);

}

しかし、Client_Xのいくつかの情報を知る必要があります。Client_xが切断されるとすぐに、パイプラインは別のSimpleChannelHandlerを作成します。だから私の情報はすべてなくなった。ChannelLocalを使用してクライアントの状態を維持しようとしています。ただし、チャネルオブジェクトに関連しているため、役に立ちません。newChannelに接続すると、古いSimpleChannelHandlersのデータを再び使用できなくなります。(clientID、roomIDなど)

私のポイントは、チャネル(セッション)の影響を受けずに情報を保存する方法です。任意のチャネルハンドラからデータにアクセスしたいと思います。

この質問を処理する方法は、このようにChannelPipelineFactoryを実装する必要がありますか?

   public class GameClientPipelineFactory implements ChannelPipelineFactory{

      private static final ClientStaticHandler SHARED = new ClientStaticHandler();  

           private Someobject o;
public GameClientPipelineFactory(Someobject refTOSomeObject) {
    super();
    this.o = refToSomeObject;
}

@Override
public ChannelPipeline getPipeline() throws Exception {
    // TODO Auto-generated method stub
    ChannelPipeline pipeline = Channels.pipeline();

    //pipeline.addLast("delimiter", new DelimiterBasedFrameDecoder(256, Delimiters.lineDelimiter()));
    pipeline.addLast("decoder", new GameClientDecoder());
    pipeline.addLast("encoder", new GameClientEncoder());
    pipeline.addLast("shared", SHARED); //I added this line

    pipeline.addLast("logicHandler", new GameClientLogicHandler(this.o));

    return pipeline;

}

しかし、この「共有」ハンドラーをどのように使用するのでしょうか。グローバルオブジェクトが必要になるたびに、このハンドラーを取得して「共有」ハンドラーからオブジェクトを取得するようにパイプラインに要求する必要がありますか?これは長い道のりではありませんか?

4

1 に答える 1

1

閉じたチャネルを再度開くのではなく、新しいチャネルを作成してみてください。

新しいチャネルの作成を開始するために、コールバックを実装することをお勧めします。

于 2012-06-11T23:43:17.283 に答える