【问题标题】:How to handle both String and HttpRequest using channelhandler in Netty in java?java - 如何在Java的Netty中使用channelhandler处理String和HttpRequest?
【发布时间】:2019-12-21 13:26:17
【问题描述】:

我想处理两个不同的客户。一种是发送字符串数据包的简单 tcp 客户端。另一种是发送httprequest msg的http客户端。我是 Netty 的初学者,我不知道管道中的处理程序是如何流动的。

这是我的服务器编码:

public class TCPServer {

    int port;

    public static void main(String[] args) {
        new TCPServer().start();
    }

    public void start() {
        port = 1222;
        EventLoopGroup producer = new NioEventLoopGroup();
        EventLoopGroup consumer = new NioEventLoopGroup();

        try {

            ServerBootstrap bootstrap = new ServerBootstrap()
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    .group(producer, consumer)//separate event loop groups to handle for parent and child for handling all chanel events
                    .channel(NioServerSocketChannel.class)//select type of chanel
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ServerAdapterInitializer());//configure chanel pipeline
            System.out.println("Server started");// configuring server channel
            bootstrap.bind(port).sync().channel().closeFuture().sync();//start the server and Wait until the server socket is closed. Thread gets blocked. 

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            producer.shutdownGracefully();
            consumer.shutdownGracefully();
        }

    }

}

这是我的 serverInitializer:

<pre>public class ServerAdapterInitializer extends ChannelInitializer<SocketChannel> {//special chanel handler configures registered chanel pipeline

    @Override
    protected void initChannel(SocketChannel channel) throws Exception {//this method is called once the chanel was registered
        ChannelPipeline pipeline = channel.pipeline();
        pipeline.addLast("decoder", new StringDecoder());//chanel inbound handler
        pipeline.addLast("encoder", new StringEncoder());
        pipeline.addLast("handler", new TCPServerHandler());

    }

}

这是我处理 httprequest 和字符串的处理程序。但我的处理程序从不处理 httprequest 数据包。

class TCPServerHandler extends SimpleChannelInboundHandler<Object> {
    private static final byte[] CONTENT = { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd' };

    private static final ChannelGroup channels = new DefaultChannelGroup("tasks", GlobalEventExecutor.INSTANCE);                                                               

    @Override
    public void channelRead0(ChannelHandlerContext ctx, Object msg)
            throws Exception {       

         if (msg instanceof HttpRequest) {
             System.out.println("http request");
            HttpRequest req = (HttpRequest) msg;

            boolean keepAlive = HttpUtil.isKeepAlive(req);
            FullHttpResponse response = new DefaultFullHttpResponse(req.protocolVersion(), OK,Unpooled.wrappedBuffer(CONTENT));
            response.headers()
                    .set(CONTENT_TYPE, TEXT_PLAIN)
                    .setInt(CONTENT_LENGTH, response.content().readableBytes());

            if (keepAlive) {
                if (!req.protocolVersion().isKeepAliveDefault()) {
                    response.headers().set(CONNECTION, KEEP_ALIVE);
                }
            } else {
                // Tell the client we're going to close the connection.
                response.headers().set(CONNECTION, CLOSE);
            }

            ChannelFuture f = ctx.write(response);

            if (!keepAlive) {
                f.addListener(ChannelFutureListener.CLOSE);
            }
        }

          if(msg instanceof String){
               System.out.println("String request");
            String arg1=(String)msg;
            Channel currentChannel = ctx.channel();
        if(arg1.equals("quit")){
            System.out.println("[INFO] - " + currentChannel.remoteAddress() + " is quitting... ");
        }else{
        System.out.println("[INFO] - " + currentChannel.remoteAddress() + " - "+ arg1);
        currentChannel.writeAndFlush("Server Said Hii "+ arg1);
        }
        }
    }

}

【问题讨论】:

    标签: string httprequest netty handler pipeline


    【解决方案1】:

    我认为不可能配置同一个服务器引导程序来处理 HTTP 请求和原始字符串消息。您需要两个服务器引导程序(一个用于 HTTP,一个用于字符串消息),每个都有自己的管道。您已经拥有用于字符串消息处理的解码器/编码器。

    EventLoopGroup producer = new NioEventLoopGroup();
    EventLoopGroup consumer = new NioEventLoopGroup();
    ServerBootstrap httpSb = new ServerBootstrap();
    ServerBootstrap strSb  = new ServerBootstrap();
    
    httpSb.group(producer, consumer).bind(<port for http>).<other methods>...
    strSb.group(producer, consumer).bind(<port for strings>).<other methods>...
    

    对于 HTTP,您需要添加处理程序 HttpServerCodecHttpObjectAggregator 才能从通道读取 FullHttpRequest 并将 FullHttpResponse 写入通道。

    (聚合器是可选的,它可以帮助您避免将分片的传入 HTTP 数据组合成单个(完整)HTTP 请求以及将组合(完整)HTTP 响应写入通道的任务)

    在 HTTP 的引导程序中:

    ch.pipeline().addLast("httpcodec"     , new HttpServerCodec());
    ch.pipeline().addLast("httpaggregator", new HttpObjectAggregator(512 * 1024));
    ch.pipeline().addLast("yourhandler"   , new YourHttpRequestHandler());
    

    FullHttpRequest 处理的示例处理程序:

    public class YourHttpRequestHandler extends ChannelInboundHandlerAdapter  {
    
    
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg_arg) 
        {
                FullHttpRequest msg = (FullHttpRequest)msg_arg;
    
                System.out.println("URI: " + msg.getUri());
                System.out.println("method: " + msg.getMethod().toString());
                System.out.println("protocol version: " + msg.getProtocolVersion()); 
                System.out.println("header1: " + msg.headers().get("header1"));
                System.out.println("header2: " + msg.headers().get("header2"));
                System.out.println("header3: " + msg.headers().get("header3"));
                System.out.println("content: " + msg.content().toString(CharsetUtil.UTF_8));
    
        }//end read
    
    }//end handler
    

    【讨论】:

    • 非常感谢。我还有一个疑问。一个服务器管道只允许一个 Inbound Outbound 处理程序和一个用户处理程序
    • 不,您可以使用任意数量的处理程序。 (并且没有“用户处理程序”之类的东西。解码器是入站处理程序,编码器是出站处理程序)
    • 对不起。我说的是我自己的处理程序。我可以添加两个处理程序吗?以及流程将如何。你能解释一下吗?
    • 传入的消息将通过入站处理程序,从左到右,直到您执行出站操作(例如,写入)。之后,您的出站处理程序将从右到左调用,直到消息离开管道。但是有一些重要的细节在 Netty 教程中有更好的解释。请务必仔细阅读。 (“从左到右”是您将处理程序添加到管道中的顺序)
    • 谢谢。请告诉我我之前问过的两个处理程序
    猜你喜欢
    • 1970-01-01
    • 2018-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-19
    • 2015-01-15
    相关资源
    最近更新 更多