Netty NIO:读取收到的消息

kon*_*tin 7 java sockets netty web

我正在使用Java中的Netty NIO开发客户端和服务器通信系统.我的代码可以在以下存储库中找到.目前我有一台服务器和两台客户端,我正在从服务器向客户端发送信息,反之亦然.

我试图弄清楚,当我接收消息形式的第一客户机到服务器,如何发送该消息到第二客户端(和从客户端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);
}
Run Code Online (Sandbox Code Playgroud)

默认情况下正在发送一个有关的连接的数量的消息,而且当我从客户机1或2我要发送回2和1因此,我要执行的两个部件之间的通信接收消息.如何从服务器发送到特定客户端?我不知道如何将消息发送回客户端.

Ser*_*nov 7

一般的做法

让我们描述一个解决问题的方法.

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

这样的识别可以使用如下的映射来完成:Map<SocketAddress, Client>其中Client类或接口应该包含适当的客户端连接(信道)关联的上下文,包括其Channel.务必使地图保持最新:适当地处理"客户连接"和"客户端连接"事件.

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

另外,我建议您使用Netty找到一个很好的聊天应用程序实现并查看它.

特定于Netty的解决方案

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

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

static final ChannelGroup channels1 =
    new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
Run Code Online (Sandbox Code Playgroud)

使频道组保持最新状态

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

@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
    channels1.add(ctx.channel());
    // ...
}
Run Code Online (Sandbox Code Playgroud)

但这只是一半:有必要对称地处理«通道变为非活动»事件.实现应该如下所示:

@Override
public void channelInactive(final ChannelHandlerContext ctx) throws Exception {
    channels1.remove(ctx.channel());
}
Run Code Online (Sandbox Code Playgroud)

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

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

@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.
        // ...
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

发送和接收字符串问题

目前,ResponseData该类的功能不存在(未实现).

要使客户端和服务器都正常工作,需要进行以下草案更改.

  1. ResponseData类:在getStringValuetoString方法应予以纠正:

    String getStringValue() {
        return this.strValue;
    }
    
    @Override
    public String toString() {
        return intValue + ";" + strValue;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  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);
    }
    
    Run Code Online (Sandbox Code Playgroud)
  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);
    }
    
    Run Code Online (Sandbox Code Playgroud)
  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());
    }
    
    Run Code Online (Sandbox Code Playgroud)

其他参考

  1. «SecureChat - 一个基于TLS的聊天服务器,源自Telnet示例»,Netty文档.特别是SecureChatServerHandler的实现.
  2. «Netty的行动»,诺曼·毛雷尔,马文·艾伦Wolfthal(ISBN-13:978-1617291470),«3部分-网络协议»的«12.2我们的示例应用程序的WebSocket»小节.涵盖«基于浏览器的聊天应用程序»的实现.