最近、Netty の実験を始めました。そして、そのようなコードを思いつきました。HttpClient を実装しますが、いくつかの制限があります。システムで許可される接続は 1 つだけです。そのため、クライアントは、古い接続が無効になった場合にのみ、新しい接続を作成することになっています。しかし、1 つのチャネルで Response/Request を 2 回送受信することはできませんでした。
私はNettyを使用しています - 4.0.2.Final
これが私の例です:
object HttpClient {
private val group: EventLoopGroup = new NioEventLoopGroup()
private val uri = new URI("http://www.google.at/")
var closed = false
def main(args: Array[String]): Unit = run
def run: Unit = {
try {
val req: HttpRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uri.getRawPath)
req.headers().set(HttpHeaders.Names.HOST, uri.getHost)
req.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE)
req.headers().set(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP)
val cl = new Bootstrap()
cl.group(group).channel(classOf[NioSocketChannel]).handler(new ChannelInitializer[SocketChannel] {
override def initChannel(ch: SocketChannel): Unit = {
val p: ChannelPipeline = ch.pipeline
p.addLast("log", new LoggingHandler(LogLevel.INFO))
p.addLast("codec", new HttpClientCodec())
p.addLast("gzip", new HttpContentDecompressor())
p.addLast("aggregator", new HttpObjectAggregator(1048576))
p.addLast("handler", new SimpleChannelInboundHandler[HttpObject] {
override def channelRead0(ctx: ChannelHandlerContext, msg: HttpObject): Unit = {
if (msg.isInstanceOf[HttpResponse]) {
val resp = msg.asInstanceOf[HttpResponse]
println(s"STATUS: ${resp.getStatus} - ${ctx.channel}")
println(s"VERSION: ${resp.getProtocolVersion} - ${ctx.channel}")
}
if(!closed) {
send(ctx.channel, req).addListener(new ChannelFutureListener(){
override def operationComplete(cf: ChannelFuture): Unit = {
println(s"it's supposed to be a second request : ${cf}")
}
})
closed = false
} else {
ctx.channel.close
}
}
override def exceptionCaught(ctx: ChannelHandlerContext, th: Throwable): Unit = {
th.printStackTrace
ctx.close
}
})
}
})
val chF = cl.connect(uri.getHost, 80).awaitUninterruptibly()
chF.addListener(new ChannelFutureListener() {
override def operationComplete(cf: ChannelFuture): Unit = {
println(s"STATUS: ${cf} ")
}
})
val ch = chF.channel
send(ch, req).addListener(new ChannelFutureListener(){
override def operationComplete(cf: ChannelFuture): Unit = {
println(s"it's a first request : ${cf}")
}
})
if(ch.isActive) println("Channel is still active")
if(ch.isOpen) println("Channel is still open")
if(ch.isWritable) println("Channel is still writable")
ch.closeFuture.addListener(new ChannelFutureListener(){
override def operationComplete(cf: ChannelFuture): Unit = {
println(s"Channel: $cf is closed")
}
}).sync
} finally {
group.shutdownGracefully
}
}
def send(ch: Channel, r: HttpRequest): ChannelFuture = ch.writeAndFlush(r)
}
実行後、次のような出力が得られます。
STATUS: DefaultChannelPromise@3f6a99fd(success)
Channel is still active
Channel is still open
Channel is still writable
it's a first request : DefaultChannelPromise@4d1a802(success)
STATUS: 200 OK - [id: 0x8e780d38, /10.0.0.8:39594 => www.google.at/173.194.113.95:80]
VERSION: HTTP/1.1 - [id: 0x8e780d38, /10.0.0.8:39594 => www.google.at/173.194.113.95:80]
it's supposed to be a second request : DefaultChannelPromise@7b88f65(failure(java.lang.ArrayIndexOutOfBoundsException: -1)
Channel: AbstractChannel$CloseFuture@3acefb4d(success) is closed
そして例外:
java.lang.ArrayIndexOutOfBoundsException: -1
at java.util.ArrayList.elementData(ArrayList.java:371)
at java.util.ArrayList.get(ArrayList.java:384)
at io.netty.handler.codec.MessageToMessageEncoder.write(MessageToMessageEncoder.java:114)
at io.netty.channel.CombinedChannelDuplexHandler.write(CombinedChannelDuplexHandler.java:193)
at io.netty.channel.DefaultChannelHandlerContext.invokeWrite0(DefaultChannelHandlerContext.java:698)
at io.netty.channel.DefaultChannelHandlerContext.access$1700(DefaultChannelHandlerContext.java:27)
at io.netty.channel.DefaultChannelHandlerContext$18.run(DefaultChannelHandlerContext.java:689)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:353)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:366)
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:101)
at java.lang.Thread.run(Thread.java:724)
2回目のリクエストで返事が来ると思っていたのですが、どうやら送信すらできていないようです。
誰か、何か提案してください。ありがとう。