I have a question about ClientBootStrap.
Here is the scenario;
- Client_X wants to join Server_A.
- But the Server_A somehow wants the Client_x to join in Server_B.
- So Server_A sends Server_B’s info to Client_X for RECONNECTION
- As soon as the Client_X gets the RECONNECTION message, he tries disconnecting from Server_A and tries to connecting to Server_B.
But it fails. Because as soon as Client disconnects from Server_A, he cannot use the disconnected channel anymore.
This looks simple. But here is my implementation
@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);
}
As you can see in the Error Line, I got this exception:java.nio.channels.ClosedChannelException. Couldn’t we use the same channel after it is disconnected?. Once it is disconnected, is it done?. How could we recreate a connection in the SimpleChannelHandler ?
Thanks for further comments 🙂
<<<<< NEW APPROACH >>>>>>
Ok. So in the SimpleChannledHandler , I use ClientBootStrap to connect a differentPort.
@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);
}
But I need to know some information of Client_X. As soon as the Client_x is disconnected the pipeline create another SimpleChannelHandler. So all my information is gone. I try to use ChannelLocal to keep state of the client. But it is also useless since it is related with channel object. When I connect to newChannel I cannot use old SimpleChannelHandlers’s data again. (like clientID,roomID etc.)
My point is how to store information without being effected by channel(session), I want to access the data from any channel handler.
The way to handle this question should we implement ChannelPipelineFactory like this?
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;
}
But then how am I gonna use this ‘shared’ handler? Each time when I need a global object, should I ask to pipeline to get this handler and get any object from ‘shared’ handler? Isn’t this a long way?
Instead of trying to reopen a closed channel, try creating a new channel.
You may want to implement a callback to initiate a the creation of a new channel.