在 netty 中接收请求并发送响应
Receive request and send response in netty
我有这样的服务器:
//...
ServerBootstrap networkServer = new ServerBootstrap();
networkServer
.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 128)
.handler(new LoggingHandler(LogLevel.TRACE))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel channel) throws Exception {
ChannelPipeline p = channel.pipeline();
p.addLast(requestHandler);
}
});
// ...
像这样的请求处理程序:
@Sharable
@Component
public class RequestHandler extends ChannelInboundHandlerAdapter {
private static final Logger logger = LogManager.getLogger(RequestHandler.class);
@Override
public void channelRead(ChannelHandlerContext ctx, Object obj) {
// (1) ctx.write(obj);
ByteBuf in = (ByteBuf) obj;
byte[] out = new byte[in.readableBytes()];
try {
int i = 0;
while (in.readableBytes() > 0) {
out[i++] = in.readByte();
}
Sproto.SProto msg = Sproto.SProto.parseFrom(out);
Sproto.SProto response = Sproto.SProto.newBuilder()
.setStatusCode(Common.ConfirmCodeStatus.OK)
.setConnectResponse(Player.ConnectResponse.newBuilder())
.build();
// (2) ctx.write(response);
// (3) ctx.write(obj);
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
}
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
logger.error(cause.getMessage(), cause);
ctx.close();
}
当我通过以下方式发回请求时:
// (1) ctx.write(obj);
它完美运行!
但是当我在解析请求后尝试发送 protobuf 响应时:
// (2) ctx.write(response);
或者只发回请求:
// (3) ctx.write(obj);
没用!我在客户端没有看到此响应。
这是怎么回事?
读取消息、执行一些逻辑并向客户端发送新响应的正确方法是什么?
您的管道在 ChannelInitializer
中初始化,只有一个处理程序:您的 requestHandler
此频道是一个 ChannelInboundHandlerAdapter
具有任何已定义类型的频道,因此它可以处理 Object
类型。因此,当收到数据包 (ByteBuf
) 时,您的处理程序将被正确调用。
然后当你调用write( object )
(你可能应该调用writeAndFlush()
)时,参数被发送到管道进行处理。如果参数是 ByteBuf
,数据将按预期写入通道连接。但如果不是,就像你的对象是 protobuf 消息的实例一样,你需要一个出站处理程序到管道中以将这种对象转换为 ByteBuf
.
Netty 提供了一个 Protobuf encoder/decoder handlers that you can add on your pipeline. But you can also extends ChannelOutboundHandlerAdapter
的实现,并编写了您自己的方式来序列化 protobuf 消息。
在您的具体情况下,您的管道应该类似于:
- 一个处理 protobuf 消息的出站处理程序,将其转换为 ByteBuf 并在管道上向下游发送
- 处理 ByteBuf 的入站处理程序,将其转换为 protobuf 消息并在管道上游向上游发送此消息
- 处理 protobuf 消息并执行某些操作(如发送响应)的入站处理程序
我有这样的服务器:
//...
ServerBootstrap networkServer = new ServerBootstrap();
networkServer
.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 128)
.handler(new LoggingHandler(LogLevel.TRACE))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel channel) throws Exception {
ChannelPipeline p = channel.pipeline();
p.addLast(requestHandler);
}
});
// ...
像这样的请求处理程序:
@Sharable
@Component
public class RequestHandler extends ChannelInboundHandlerAdapter {
private static final Logger logger = LogManager.getLogger(RequestHandler.class);
@Override
public void channelRead(ChannelHandlerContext ctx, Object obj) {
// (1) ctx.write(obj);
ByteBuf in = (ByteBuf) obj;
byte[] out = new byte[in.readableBytes()];
try {
int i = 0;
while (in.readableBytes() > 0) {
out[i++] = in.readByte();
}
Sproto.SProto msg = Sproto.SProto.parseFrom(out);
Sproto.SProto response = Sproto.SProto.newBuilder()
.setStatusCode(Common.ConfirmCodeStatus.OK)
.setConnectResponse(Player.ConnectResponse.newBuilder())
.build();
// (2) ctx.write(response);
// (3) ctx.write(obj);
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
}
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
logger.error(cause.getMessage(), cause);
ctx.close();
}
当我通过以下方式发回请求时:
// (1) ctx.write(obj);
它完美运行!
但是当我在解析请求后尝试发送 protobuf 响应时:
// (2) ctx.write(response);
或者只发回请求:
// (3) ctx.write(obj);
没用!我在客户端没有看到此响应。
这是怎么回事? 读取消息、执行一些逻辑并向客户端发送新响应的正确方法是什么?
您的管道在 ChannelInitializer
中初始化,只有一个处理程序:您的 requestHandler
此频道是一个 ChannelInboundHandlerAdapter
具有任何已定义类型的频道,因此它可以处理 Object
类型。因此,当收到数据包 (ByteBuf
) 时,您的处理程序将被正确调用。
然后当你调用write( object )
(你可能应该调用writeAndFlush()
)时,参数被发送到管道进行处理。如果参数是 ByteBuf
,数据将按预期写入通道连接。但如果不是,就像你的对象是 protobuf 消息的实例一样,你需要一个出站处理程序到管道中以将这种对象转换为 ByteBuf
.
Netty 提供了一个 Protobuf encoder/decoder handlers that you can add on your pipeline. But you can also extends ChannelOutboundHandlerAdapter
的实现,并编写了您自己的方式来序列化 protobuf 消息。
在您的具体情况下,您的管道应该类似于:
- 一个处理 protobuf 消息的出站处理程序,将其转换为 ByteBuf 并在管道上向下游发送
- 处理 ByteBuf 的入站处理程序,将其转换为 protobuf 消息并在管道上游向上游发送此消息
- 处理 protobuf 消息并执行某些操作(如发送响应)的入站处理程序