java 如何在 Netty 中使用 channelhandler 处理 String 和 HttpRequest?
How to handle both String and HttpRequest using channelhandler in Netty in java?
我想处理两个不同的客户。一种是发送字符串数据包的简单 tcp 客户端。另一个是发送 httprequest 消息的 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);
}
}
}
}
我认为不可能配置同一个服务器 bootstrap 来处理 HTTP 请求和原始字符串消息。您需要两台服务器 bootstrap(一台用于 HTTP,一台用于字符串消息),每个服务器都有自己的管道。您已经有了用于字符串消息处理的 decoder/encoder。
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,您需要添加处理程序 HttpServerCodec
和 HttpObjectAggregator
才能从通道读取 FullHttpRequest
并将 FullHttpResponse
写入通道。
(聚合器是可选的,它可以帮助您避免将碎片化的传入 HTTP 数据组合成单个(完整)HTTP 请求以及将组合(完整)HTTP 响应写入通道的任务)
在 bootstrap 中用于 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
我想处理两个不同的客户。一种是发送字符串数据包的简单 tcp 客户端。另一个是发送 httprequest 消息的 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);
}
}
}
}
我认为不可能配置同一个服务器 bootstrap 来处理 HTTP 请求和原始字符串消息。您需要两台服务器 bootstrap(一台用于 HTTP,一台用于字符串消息),每个服务器都有自己的管道。您已经有了用于字符串消息处理的 decoder/encoder。
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,您需要添加处理程序 HttpServerCodec
和 HttpObjectAggregator
才能从通道读取 FullHttpRequest
并将 FullHttpResponse
写入通道。
(聚合器是可选的,它可以帮助您避免将碎片化的传入 HTTP 数据组合成单个(完整)HTTP 请求以及将组合(完整)HTTP 响应写入通道的任务)
在 bootstrap 中用于 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