连接上的Netty消息

连接上的Netty消息,netty,Netty,我刚刚开始学习Netty,想慢慢来真正理解它是如何工作的。我有一个基于独立套接字测试程序的初始用例: 从客户端连接到服务器时,立即发送消息并处理响应 很容易…至少我是这么想的。我已经看了好几天了,但并没有真正理解为什么它的表现不如预期 这里是原始的测试程序,它再次简单地连接到远程服务器,并立即将bytebuffer写入服务器。然后,服务器立即发送一个刚刚写入控制台的ack响应 import java.io.*; import java.nio.ByteBuffer; import java.

我刚刚开始学习Netty,想慢慢来真正理解它是如何工作的。我有一个基于独立套接字测试程序的初始用例:

  • 从客户端连接到服务器时,立即发送消息并处理响应
很容易…至少我是这么想的。我已经看了好几天了,但并没有真正理解为什么它的表现不如预期

这里是原始的测试程序,它再次简单地连接到远程服务器,并立即将bytebuffer写入服务器。然后,服务器立即发送一个刚刚写入控制台的ack响应

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.net.*;
import java.util.StringTokenizer;
import java.nio.charset.StandardCharsets;

public class SocketTest {
  public static void main(String[] args) throws IOException {

    final String host = "remote host";
    final int port = 123456;

    final String msg = "hi";
    final byte sync = (byte)0x02;
    final short value1 = (short)70;
    final byte value2 = (byte)12;
    final byte value3 = (byte)0x4c;
    final int value4 = 1;
    final short value5 = (short)0x03;
    final short value6 = (short)0xffff;

    try {
      SocketChannel socketChannel
          = SocketChannel.open(new InetSocketAddress(host, port));

       ByteBuffer buf = ByteBuffer.allocate(15);
       buf.put(sync);
       buf.putShort(value1);
       buf.put(value2);
       buf.put(value3);
       buf.putInt(value4);
       buf.putShort(value5);
       buf.putShort(value6);
       buf.put(msg.getBytes(StandardCharsets.UTF_8));
       buf.flip();

       //write
       while(buf.hasRemaining()) {
         socketChannel.write(buf);
       }

       //read
       ByteBuffer inBuf = ByteBuffer.allocate(78);
       while (socketChannel.read(inBuf) > 0) {
           System.out.printf("[%s]:\t%s\n", Thread.currentThread().getName(), new String(inBuf.array(), StandardCharsets.UTF_8));
       }
    } catch(UnknownHostException e) {
      System.exit(1);
    } catch(IOException ioe) {
      System.exit(1);
    } finally {
      socketChannel.close();
    }
  }
}
我进行了相同的测试,并使用Netty尝试了这个基本用例:

NettySocketTest

import java.net.InetSocketAddress;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelFuture;
import io.netty.channel.socket.SocketChannel;

public class NettySocketTest {

  private final String host;
  private final int port;
  private SocketChannel channelInstance;

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

  public void start() throws Exception {
    EventLoopGroup group = new NioEventLoopGroup();

    try {
      Bootstrap b = new Bootstrap();
      b.group(group)
        .channel(NioSocketChannel.class)
        .remoteAddress(new InetSocketAddress(host, port))
        .handler(new ChannelInitializer<SocketChannel>() {
          @Override
          public void initChannel (SocketChannel channel) throws Exception {
            channel.pipeline().addLast(new ClientTestHandler());
          }
        });

      ChannelFuture f = b.connect().sync();
      f.channel().closeFuture().sync();
    } catch(Exception e) {
      e.printStackTrace();
    }finally {
      group.shutdownGracefully().sync();
    }
  }
}
在ClientTestHandler中:

  • 我使用了现有的ByteBuffer代码,并在转换为Netty提供的方便方法之前尝试按原样使用它。见#2
  • 这是尝试使用CompositeByteBuf。1或2都不起作用
  • 尝试使用ChannelHandlerContext写出消息,另一个尝试直接在上下文上使用该通道,希望其中一个会非法响应
  • 我的期望是将消息发送到服务器,并将响应打印到控制台

    客户端代码执行以下操作:

  • 成功启动/连接
  • 成功调用channelActive
  • 在ChannelFutureListener上成功调用operationComplete
  • 永远不会调用channelRead0方法
  • 我故意没有向管道中添加任何其他内容,这样我就可以简单地开始修改代码,并边走边学习。我将CompositeByteBuf恢复为nio.ByteBuffer,这样我就可以从另一个测试中的代码开始


    连接时使用channelActive立即向服务器发送字节是否正确?有谁能帮助我理解我在这个基本用例中犯了什么错误,以及为什么没有捕获响应(假设消息确实已发送)?

    您的问题是因为在将处理程序添加到管道时,它已经连接。这与客户端不同,客户端仍然需要解析服务器的ip地址并打开与服务器的连接

    您应该覆盖p
    channelRegistered
    ](),并使用
    ctx.channel().isActive()
    上的if语句检查频道是否已处于活动状态,如果处于活动状态,则直接开始发送消息


    请注意,对于大多数协议,最好让客户端先发送一些内容,因为在这种情况下,攻击者无法从随机端口快速获取您的应用程序名称和版本,并允许端口统一,在同一端口上运行多个服务。

    您使用的
    channelActive
    仅是正确的,例如,它用于向服务器发送第一条消息(例如握手、建立连接等)。我怀疑服务器没有向客户端回复任何内容。请共享您的服务器代码。服务器是第三方提供商,其服务器代码是专有的。如图所示,将nio.ByteBuffer传递到write中是否正确?我不明白为什么非Netty代码会得到响应,但其中的相同缓冲区定义却没有。你能用Netty
    ByteBuf
    来代替吗?当然。如果您检查ClientHandler类,我尝试使用compositebytebuf进行测试(我无法实现),但从未尝试过直接使用bytebuf。我可以试一试。ChannelFuture(我从示例代码中使用)就是问题所在。关闭通道会阻止接收来自服务器的响应。删除侦听器后,一切都按预期进行!
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.SimpleChannelInboundHandler;
    import io.netty.channel.ChannelFutureListener;
    import io.netty.buffer.CompositeByteBuf;
    import io.netty.buffer.Unpooled;
    import io.netty.buffer.ByteBuf;
    import java.nio.ByteBuffer;
    import java.nio.charset.StandardCharsets;
    
    public class ClientTestHandler extends SimpleChannelInboundHandler {
    
      final String msg = "hi";
    
      @Override
      public void channelActive(final ChannelHandlerContext ctx) {
        //existing test code - [1]
        ByteBuffer buf = ByteBuffer.allocate(15);
        buf.put((byte)0x02);
        buf.putShort((short)70);
        buf.put((byte)12);
        buf.put((byte)0x4c);
        buf.putInt(101);
        buf.putShort((short)0x03);
        buf.putShort((short)0xffff);
        buf.put(msg.getBytes(StandardCharsets.UTF_8));
        buf.flip();
    
        //preferred implementation - [2]
        /**
        CompositeByteBuf messageBuf = Unpooled.compositeBuffer();
        ByteBuf syncBuf = ctx.alloc().buffer(1);
        syncBuf.writeByte((byte)0x02);
    
        ByteBuf headerBuf = ctx.alloc().buffer(12);
        headerBuf.writeShort((short)70);
        headerBuf.writeByte((byte)12);
        headerBuf.writeByte((byte)0x4c);
        headerBuf.writeInt(101);
        headerBuf.writeShort((short)0x03);
        headerBuf.writeShort((short)0xffff);
    
        ByteBuf bodyBuf = ctx.alloc().buffer(2);
        bodyBuf.writeBytes("hi".getBytes(StandardCharsets.UTF_8));
        messageBuf.addComponents(syncBuf, headerBuf, bodyBuf);
        **/
    
        //DOESN'T WORK - [3]
        final ChannelFuture f = ctx.writeAndFlush(buf);
    
        //ALSO DOESN'T WORK 
        //final ChannelFuture f = ctx.channel().writeAndFlush(buf);
    
          f.addListener(new ChannelFutureListener() {
              @Override
              public void operationComplete(ChannelFuture future) {
                  assert f == future;
                  ctx.close();
              }
          });
        }
    
      @Override
      public void channelRead0(ChannelHandlerContext ctx, Object resp) {
        ByteBuf msg = (ByteBuf) resp;
        System.out.println("Response received: " + msg.toString(StandardCharsets.UTF_8));
      }
    
      @Override
      public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
      }
    }