简体   繁体   English

Netty在没有for循环的情况下向Server发送消息

[英]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: 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. 我尝试了一些调试步骤,服务器将客户端添加到其通道,并在客户端成功执行channelActive。

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). 您应该尝试将通信转移到处理程序(您的ChatClientInitializer或您最后添加的额外处理程序),而不是轮询整个变量。 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: 一个非常基本的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 {
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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