I want to handle two different clients. One is simple tcp client which sends string packets. Another one is http client which sends httprequest msg. I am a beginner in Netty, I don't know how handlers in pipelines flow.
This is my server coding:
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();
}
}
}
This is my 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());
}
}
And this my handler to handle both httprequest and string. But my handler never handle httprequest packet.
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);
}
}
}
}
I don't think it is possible to configure the same server bootstrap to handle both HTTP requests and raw String messages. You need two server bootstraps (one for HTTP, one for String messages) each with its own pipeline. You already have the decoder/encoder for String message handling.
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>...
For HTTP, you need to add handlers HttpServerCodec
and HttpObjectAggregator
to be able to read FullHttpRequest
from the channel and write FullHttpResponse
into the channel.
(aggregator is optional, it helps you to avoid the task of combining fragmented incoming HTTP data into a single (full) HTTP request as well as write a combined (full) HTTP response into the channel)
In bootstrap for HTTP:
ch.pipeline().addLast("httpcodec" , new HttpServerCodec());
ch.pipeline().addLast("httpaggregator", new HttpObjectAggregator(512 * 1024));
ch.pipeline().addLast("yourhandler" , new YourHttpRequestHandler());
Example handler for FullHttpRequest
processing:
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