我有一个关于 ClientBootStrap 的问题。这是场景;
- Client_X 想加入 Server_A。
- 但是 Server_A 以某种方式希望 Client_x 加入 Server_B。
- 所以 Server_A 将 Server_B 的信息发送给 Client_X 进行 RECONNECTION
- 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 中重新创建连接?
感谢您的进一步评论:)
<<<<< 新方法>>>>>>
好的。所以在 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;
}
但是我将如何使用这个“共享”处理程序?每次我需要一个全局对象时,我是否应该要求管道获取此处理程序并从“共享”处理程序获取任何对象?这不是很长的路吗?