I'm trying to understand netty ChannelPool. I'm following the tutorial https://www.programmerall.com/article/74872253762/ to for that.
Below is the http URL that is working fine in curl cli.
curl --location 'https://httpbin.org/get'
{
"args": {},
"headers": {
"Accept": "*/*",
"Host": "httpbin.org",
"User-Agent": "curl/8.1.2",
"X-Amzn-Trace-Id": "Root=1-6500a506-7e7997ac222e1bc56e85a4e6"
},
"origin": "52.34.203.106",
"url": "https://httpbin.org/get"
}
I modified the code in the above tutorial to invoke this service. Just the URL and host and port part of the ChannelPool.
Below is the complete code -
NettyClientHandler.java is -
```java
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.util.CharsetUtil;
import java.util.concurrent.atomic.AtomicInteger;
public class NettyClientHandler extends ChannelInboundHandlerAdapter {
static AtomicInteger count = new AtomicInteger(1);
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
FullHttpResponse response = (FullHttpResponse) msg;
ByteBuf content = response.content();
System.out.println(count.getAndIncrement()+": content:"+content.toString(CharsetUtil.UTF_8));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
}
}
NettyChannelPoolHandler is -
import io.netty.channel.Channel;
import io.netty.channel.pool.ChannelPoolHandler;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpContentDecompressor;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.timeout.IdleStateHandler;
public class NettyChannelPoolHandler implements ChannelPoolHandler {
@Override
public void channelReleased(Channel channel) throws Exception {
System.out.println("channelReleased. Channel ID:"+channel.id());
}
@Override
public void channelAcquired(Channel channel) throws Exception {
System.out.println("channelAcquired. Channel ID:"+channel.id());
}
@Override
public void channelCreated(Channel channel) throws Exception {
System.out.println("channelCreated. Channel ID:"+channel.id());
SocketChannel socketChannel = (SocketChannel) channel;
socketChannel.config().setKeepAlive(true);
socketChannel.config().setTcpNoDelay(true);
socketChannel.pipeline()
.addLast(new HttpClientCodec())
.addLast(new HttpObjectAggregator(1024 * 10 * 1024))
.addLast(new HttpContentDecompressor())
.addLast(new NettyClientHandler());
channel.pipeline().addFirst(new IdleStateHandler(5, 5, 10));
}
}
Finally the main program ChannelPoolDemo is -
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.pool.AbstractChannelPoolMap;
import io.netty.channel.pool.ChannelPoolMap;
import io.netty.channel.pool.FixedChannelPool;
import io.netty.channel.pool.SimpleChannelPool;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.*;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URL;
import java.nio.charset.Charset;
public class ChannelPoolDemo {
final EventLoopGroup group = new NioEventLoopGroup();
final Bootstrap bootstrap = new Bootstrap();
ChannelPoolMap<InetSocketAddress, SimpleChannelPool> poolMap;
public void build() throws Exception{
bootstrap.group(group)
.channel(NioSocketChannel.class)
//Connection timeout
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000)
.option(ChannelOption.TCP_NODELAY,true)
.option(ChannelOption.SO_KEEPALIVE,true)
.handler(new LoggingHandler(LogLevel.ERROR));
poolMap = new AbstractChannelPoolMap<InetSocketAddress, SimpleChannelPool>() {
@Override
protected SimpleChannelPool newPool(InetSocketAddress inetSocketAddress) {
return new FixedChannelPool(bootstrap.remoteAddress(inetSocketAddress),new NettyChannelPoolHandler(),2);
}
};
}
public static void main(String[] args) {
testHttp();
}
public static void testHttp(){
try {
ChannelPoolDemo client = new ChannelPoolDemo();
client.build();
String url = "https://httpbin.org/get";
HttpRequest fullHttpRequest = buildRequest(url, true);
SimpleChannelPool pool = client.poolMap.get(new InetSocketAddress("httpbin.org", 80));
Future<Channel> f = pool.acquire();
f.addListener((FutureListener<Channel>) f1->{
if(f1.isSuccess()){
Channel ch = f1.getNow();
System.out.println(fullHttpRequest);
fullHttpRequest.headers().forEach(x -> System.out.println(x.getKey() + "\t" + x.getValue()));
ChannelFuture channelFuture = ch.writeAndFlush(fullHttpRequest);
channelFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) {}
});
pool.release(ch);
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
public static HttpRequest buildRequest(String url, boolean isKeepAlive) throws Exception {
URL netUrl = new URL(url);
URI uri = new URI(netUrl.getPath());
System.out.println(uri.toASCIIString());
DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uri.toASCIIString());
return request;
}
}
when I run the program I get the below response always -
/get
request content:
channelCreated. Channel ID:76f0e7e9
channelAcquired. Channel ID:76f0e7e9
DefaultFullHttpRequest(decodeResult: success, version: HTTP/1.1, content: UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 0, cap: 0))
GET /get HTTP/1.1
channelReleased. Channel ID:76f0e7e9
1: content:<html>
<head><title>400 Bad Request</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
</body>
</html>
What is wrong with my program? Why it is always returning 404 when it works in curl?
I think probably I'm not correctly creating InetSocketAddress for ChannelPool correctly. How can I fix this?