代码之家  ›  专栏  ›  技术社区  ›  konstantin

Netty NIO:读取收到的消息

  •  7
  • konstantin  · 技术社区  · 8 年前

    我正在用Java中的Netty NIO开发一个客户机和服务器通信系统。可以找到我的代码 in the following repository . 目前,我有一个服务器和两个客户端,我正在从服务器向客户端和相反的客户端发送信息。

    我想知道的是,当我从第一个客户端接收到一条消息到服务器时,如何将该消息发送到第二个客户端(从客户端2到客户端1)。如何向特定客户发送消息?

    我注意到我的问题是因为我试图从服务器发送消息的方式。我在serverHandler中的代码如下:

    for (Channel ch : channels1) {
        responseData.setIntValue(channels1.size());
        remoteAddr.add(ch.remoteAddress().toString());
        future = ch.writeAndFlush(responseData);
        //future.addListener(ChannelFutureListener.CLOSE);
        System.out.println("the requested data from the clients are: "+requestData);
        responseData1.setStringValue(requestData.toString());
        future = ch.writeAndFlush(responseData1);
        System.out.println(future);
    }
    

    默认情况下,我会发送一条关于连接数的消息,但当我从客户端1或2收到消息时,我也想将其发送回2和1。所以我想在这两个组件之间进行通信。如何从服务器发送到特定客户端?我不知道如何将这些信息发送回客户。

    1 回复  |  直到 8 年前
        1
  •  7
  •   Sergey Vyacheslavovich Brunov prodigitalson    8 年前

    一般方法

    让我们描述一种解决问题的方法。

    在服务器端接收数据时,使用通道的远程地址(即 java.net.SocketAddress Channel.remoteAddress() method )识别客户。

    Map<SocketAddress, Client> ,其中 Client 类或接口应包含相应的客户端连接(通道)关联上下文,包括其 Channel . 确保地图保持最新:适当处理«client connected»和«client disconnected»事件。

    识别客户端后,您可以使用客户端连接(通道)映射将适当的消息发送到客户端(当前发送客户端除外)。

    此外,我想推荐您使用Netty找到一个很好的聊天应用程序实现,并看看它。

    Netty特定解决方案

    让我们考虑服务器端实现,特别是 ProcessingHandler

    它已经通过将活动通道表示为通道组来管理它们:

    static final ChannelGroup channels1 =
        new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    

    当前实现处理通道变为活动事件,以使通道组保持最新:

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        channels1.add(ctx.channel());
        // ...
    }
    

    但这仅仅是一半:还需要对称地处理通道变为非活动事件。实现应该如下所示:

    @Override
    public void channelInactive(final ChannelHandlerContext ctx) throws Exception {
        channels1.remove(ctx.channel());
    }
    

    广播:将接收到的消息发送到除当前频道外的所有频道

    要实现所需的行为,只需通过引入适当的检查来更新实现,如下所示:

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        // ...
    
        for (Channel ch : channels1) {
            // Does `ch` represent the channel of the current sending client?
            if (ch.equals(ctx.channel())) {
                // Skip.
                continue;
            }
    
            // Send the message to the `ch` channel.
            // ...
        }
    
        // ...
    }
    

    发送和接收字符串问题

    Currently ,围绕 ResponseData 类不存在(未实现)。

    以下内容 草稿 需要进行更改才能使客户端和服务器都工作。

    1. 这个 响应数据 类别:the getStringValue toString 应纠正方法:

      String getStringValue() {
          return this.strValue;
      }
      
      @Override
      public String toString() {
          return intValue + ";" + strValue;
      }
      
    2. 这个 ResponseDataEncoder 类:它应该使用字符串值:

      private final Charset charset = Charset.forName("UTF-8");
      
      @Override
      protected void encode(final ChannelHandlerContext ctx, final ResponseData msg, final ByteBuf out) throws Exception {
          out.writeInt(msg.getIntValue());
          out.writeInt(msg.getStringValue().length());
          out.writeCharSequence(msg.getStringValue(), charset);
      }
      
    3. 这个 ResponseDataDecoder

      private final Charset charset = Charset.forName("UTF-8");
      
      @Override
      protected void decode(final ChannelHandlerContext ctx, final ByteBuf in, final List<Object> out) throws Exception {
          ResponseData data = new ResponseData();
          data.setIntValue(in.readInt());
          int strLen = in.readInt();
          data.setStringValue(in.readCharSequence(strLen, charset).toString());
          out.add(data);
      }
      
    4. 这个 ClientHandler 类:它应该正确接收和处理消息:

      @Override
      public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
          final ResponseData responseData = (ResponseData) msg;
          System.out.println("The message sent from the server " + responseData);
          update.accept(responseData.getIntValue());
      }
      

    其他参考文献

    1. «SecureChat ‐ an TLS-based chat server, derived from the Telnet example», Netty Documentation SecureChatServerHandler class .
    2. «Netty in Action», Norman Maurer, Marvin Allen Wolfthal (ISBN-13: 978-1617291470) ,第3部分网络协议,12.2我们的示例WebSocket应用程序子章。介绍了基于浏览器的聊天应用程序的实现。