Netty: What is the right way to share NioClientSocketChannelFactory among multiple Netty Clients

StackOverflow https://stackoverflow.com/questions/17933798

  •  04-06-2022
  •  | 
  •  

Pregunta

I am new to Netty. I am using “Netty 3.6.2.Final”. I have created a Netty Client (MyClient) that talks to a remote server (The server implements a custom protocol based on TCP). I create a new ClientBootstrap instance for each MyClient instance (within the constructor). My question is if I share “NioClientSocketChannelFactory” factory object among all the instances of MyClient then when/how do I release all the resources associated with the “NioClientSocketChannelFactory”?

In other words, since my Netty Client runs inside a JBOSS container running 24x7, should I release all resources by calling “bootstrap.releaseExternalResources();” and when/where should I do so?

More Info: My Netty Client is called from two scenarios inside a JBOSS container. First, in an infinite for loop with each time passing the string that needs to be sent to the remote server (in effect similar to below code)

for( ; ; ){
    //Prepare the stringToSend
    //Send a string and receive a string
String returnedString=new MyClient().handle(stringToSend);
}

Another scenarios is my Netty Client is called within concurrent threads with each thread calling “new MyClient().handle(stringToSend);”.

I have given the skeleton code below. It is very similar to the TelnetClient example at Netty website.

MyClient

import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
public class MyClient {
    //Instantiate this only once per application
    private final static Timer timer = new HashedWheelTimer();

    //All below must come from configuration
    private final String host ="127.0.0.1";
    private final int port =9699; 
    private final InetSocketAddress address = new InetSocketAddress(host, port);
    private ClientBootstrap bootstrap;

    //Timeout when the server sends nothing for n seconds.
        static final int READ_TIMEOUT = 5;

        public MyClient(){
            bootstrap = new ClientBootstrap(NioClientSocketFactorySingleton.getInstance());
        }

    public String handle(String messageToSend){
        bootstrap.setOption("connectTimeoutMillis", 20000);
            bootstrap.setOption("tcpNoDelay", true);
            bootstrap.setOption("keepAlive", true);
            bootstrap.setOption("remoteAddress", address);
        bootstrap.setPipelineFactory(new MyClientPipelineFactory(messageToSend,bootstrap,timer));

         // Start the connection attempt.
            ChannelFuture future = bootstrap.connect();

            // Wait until the connection attempt succeeds or fails.
            channel = future.awaitUninterruptibly().getChannel();


            if (!future.isSuccess()) { 
                return null;  
            }

            // Wait until the connection is closed or the connection attempt fails.
            channel.getCloseFuture().awaitUninterruptibly();

            MyClientHandler myClientHandler=(MyClientHandler)channel.getPipeline().getLast();
            String messageReceived=myClientHandler.getMessageReceived();
        return messageReceived;
    }
}

Singleton NioClientSocketChannelFactory

public class NioClientSocketFactorySingleton {
private static NioClientSocketChannelFactory nioClientSocketChannelFactory;

private NioClientSocketFactorySingleton() {
}

public static synchronized NioClientSocketChannelFactory getInstance() {
    if ( nioClientSocketChannelFactory == null) {
        nioClientSocketChannelFactory=new NioClientSocketChannelFactory(
            Executors.newCachedThreadPool(),
            Executors.newCachedThreadPool());
    }
    return  nioClientSocketChannelFactory;
 }

  protected void finalize() throws Throwable {
    try{
    if(nioClientSocketChannelFactory!=null){    
        // Shut down thread pools to exit.
        nioClientSocketChannelFactory.releaseExternalResources();
    } 
    }catch(Exception e){
    //Can't do anything much
    }
  }
} 

MyClientPipelineFactory

public class MyClientPipelineFactory implements ChannelPipelineFactory {

    private String messageToSend;
    private ClientBootstrap bootstrap;
    private Timer timer;
    public MyClientPipelineFactory(){

    }
    public MyClientPipelineFactory(String messageToSend){
        this.messageToSend=messageToSend;
    }

    public MyClientPipelineFactory(String messageToSend,ClientBootstrap bootstrap, Timer timer){
        this.messageToSend=messageToSend;
        this.bootstrap=bootstrap;
        this.timer=timer;
    }

        public ChannelPipeline getPipeline() throws Exception {

            // Create a default pipeline implementation.
            ChannelPipeline pipeline = pipeline();

            // Add the text line codec combination first,
            //pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
            pipeline.addLast("decoder", new StringDecoder());
            pipeline.addLast("encoder", new StringEncoder());

            //Add readtimeout
            pipeline.addLast("timeout", new ReadTimeoutHandler(timer, MyClient.READ_TIMEOUT));

            // and then business logic.
            pipeline.addLast("handler", new MyClientHandler(messageToSend,bootstrap));


            return pipeline;
        }
}

MyClientHandler

public class MyClientHandler extends SimpleChannelUpstreamHandler { 

    private String messageToSend="";
    private String messageReceived="";


    public MyClientHandler(String messageToSend,ClientBootstrap bootstrap) {
        this.messageToSend=messageToSend;
        this.bootstrap=bootstrap;
    }

    @Override
    public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e){
        e.getChannel().write(messageToSend);
    }

    @Override
    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e){
        messageReceived=e.getMessage().toString();
    //This take the control back to the MyClient
    e.getChannel().close();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
        // Close the connection when an exception is raised.
        e.getChannel().close();

    }


}
¿Fue útil?

Solución

You should only call releaseExternalResources() once you are sure you not need it anymore. This may be for example when the application gets stopped or undeployed.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top