简体   繁体   中英

Netty send message to Server without for loop

I was using the following code to send messages from the Client to the Server:

Client class:

public class Client {

  String host = "localhost";
  int port = 14930;
  private final ClientHandler clientHandler = new ClientHandler();

  public Client(String host, int port) {
    this.host = host;
    this.port = port;
  }

  public void run() throws Exception {

    try {
      workerGroup = new NioEventLoopGroup();
      Bootstrap b = new Bootstrap();
      b.group(workerGroup);
      b.channel(NioSocketChannel.class);
      b.option(ChannelOption.SO_KEEPALIVE, true);
      b.handler(new ChannelInitializer<SocketChannel>() {
        @Override
          public void initChannel(SocketChannel ch) throws Exception {
          ChannelPipeline pipeline = ch.pipeline();
          pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
          pipeline.addLast(new StringDecoder());
          pipeline.addLast(new StringEncoder());
          pipeline.addLast(clientHandler);
        }
      }
      );

      ChannelFuture f = b.connect(host, port).sync();

      f.channel().closeFuture().sync();
    }
    finally {
      workerGroup.shutdownGracefully();
    }
  }
  public void writeMessage(String msg) {
    clientHandler.sendMessage(msg);
  }
}

Handler class:

public class ClientHandler extends SimpleChannelInboundHandler<String> {
  ChannelHandlerContext ctx;

  public void sendMessage(String msgToSend) {
    ctx.writeAndFlush(Unpooled.copiedBuffer(msgToSend, CharsetUtil.UTF_8));
  }

  @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
    this.ctx = ctx;
  }

  @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
    cause.printStackTrace();
    ctx.close();
  }

  @Override
    protected void channelRead0(ChannelHandlerContext arg0, String msg) throws Exception {
  }

  void channelInactive(ChannelHandlerContext ctx) throws Exception {
  }
}

I am creating the Client like this:

Client client;
client = new Client(ipAddress, serverPort);
client.run();
client.writeMessage("random_text");

The Server:

public final class ChatServer {

  public ChatServer(int PORT) throws Exception {

    bossGroup = new NioEventLoopGroup();
    workerGroup = new NioEventLoopGroup();

    try {
      ServerBootstrap b = new ServerBootstrap();
      b.group(bossGroup, workerGroup)
        .channel(NioServerSocketChannel.class)
          .handler(new LoggingHandler(LogLevel.INFO))
            .childHandler(new ChatServerInitializer());

      b.bind(PORT).sync().channel().closeFuture().sync();
    } 
    finally {
      bossGroup.shutdownGracefully();
      workerGroup.shutdownGracefully();
    }
  }
}

ServerHandler:

public class ChatServerHandler extends SimpleChannelInboundHandler<String> {

  public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
    Channel incoming = ctx.channel();
    channels.add(ctx.channel());
  }

  public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
    Channel incoming = ctx.channel();
    channels.remove(ctx.channel());
  } 

  @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
    cause.printStackTrace();
    ctx.close();
  }

  @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
    println(msg);
  }
}

Method to send Message from Server to Client:

public void sendMessage(String message) {
  if (message != "" && message != null) {
    for (Channel c : channels) {
      c.writeAndFlush(message + "\r\n");
    }
  }
}

The problem is that the Server does not get any Messages. I tried some debug steps, the Server adds the Client to its channels, and channelActive gets executed successfully on the Client side.

Instead of polling the variable the whole time you should try to transfer the communication to the handler (either your ChatClientInitializer or an extra handler that you add last). Give this handler a method that you call when a new message was entered. The handler then writes to the channel.

Maybe this example helps:

public class Client implements Runnable {

    String host = "localhost";
    int port = 9128;
    private final ClientHandler clientHandler = new ClientHandler();
    private boolean isRunning = false;
    private ExecutorService executor = null;


    public static void main(String[] args) {
        Client client = new Client();
        client.startClient();
        client.writeMessage("random_text");
        //client.stopClient();  //call this at some point to shutdown the client
    }

    public synchronized void startClient() {
        if (!isRunning) {
            executor = Executors.newFixedThreadPool(1);
            executor.execute(this);
            isRunning = true;
        }
    }

    public synchronized boolean stopClient() {
        boolean bReturn = true;
        if (isRunning) {
            if (executor != null) {
                executor.shutdown();
                try {
                    executor.shutdownNow();
                    if (executor.awaitTermination(calcTime(10, 0.66667), TimeUnit.SECONDS)) {
                        if (!executor.awaitTermination(calcTime(10, 0.33334), TimeUnit.SECONDS)) {
                            bReturn = false;
                        }
                    }
                } catch (InterruptedException ie) {
                    executor.shutdownNow();
                    Thread.currentThread().interrupt();
                } finally {
                    executor = null;
                }
            }
            isRunning = false;
        }
        return bReturn;
    }

    private long calcTime(int nTime, double dValue) {
        return (long) ((double) nTime * dValue);
    }

    @Override
    public void run() {
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(workerGroup);
            b.channel(NioSocketChannel.class);
            b.option(ChannelOption.SO_KEEPALIVE, true);
            b.handler(new ChannelInitializer<SocketChannel>() {
                @Override
                public void initChannel(SocketChannel ch) throws Exception {
                    ChannelPipeline pipeline = ch.pipeline(); 
                    pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
                    pipeline.addLast(new StringDecoder());
                    pipeline.addLast(new StringEncoder());
                    pipeline.addLast(clientHandler);
                }
            });

            ChannelFuture f = b.connect(host, port).sync();

            f.channel().closeFuture().sync();
        } catch (InterruptedException ex) {
            // do nothing
        } finally {
            workerGroup.shutdownGracefully();
        }
    }

    public void writeMessage(String msg) {
        clientHandler.sendMessage(msg);
    }
}

A very basic ClientHandler:

public class ClientHandler extends SimpleChannelInboundHandler<String> {
    ChannelHandlerContext ctx;

    public void sendMessage(String msgToSend) {
        if (ctx != null) {
            ChannelFuture cf = ctx.write(Unpooled.copiedBuffer(msgToSend, CharsetUtil.UTF_8));
            ctx.flush();
            if (!cf.isSuccess()) {
                System.out.println("Send failed: " + cf.cause());
            }
        } else {
            //ctx not initialized yet. you were too fast. do something here
        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        this.ctx = ctx;
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }

    @Override
    protected void channelRead0(ChannelHandlerContext arg0, String msg) throws Exception {
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM