java - Netty - Reuse Channel for periodic HTTP requests -
i want establish connection https server (for example google.com) , periodically obtain fresh content.
i wrote simple http client:
public class asyncloader { private static final string host = "google.com"; private static final int port = 443; public static void main(string[] args) throws interruptedexception, ioexception, urisyntaxexception { final sslcontext sslctx = sslcontextbuilder.forclient().trustmanager(insecuretrustmanagerfactory.instance).build(); eventloopgroup elg = new nioeventloopgroup(); bootstrap cb = new bootstrap() .option(channeloption.tcp_nodelay, true) .option(channeloption.so_keepalive, true) .option(channeloption.so_reuseaddr, false) .option(channeloption.allocator, pooledbytebufallocator.default) .group(elg) .channel(niosocketchannel.class) .remoteaddress(host, port) .handler(new channelinitializer<socketchannel>() { @override protected void initchannel(socketchannel ch) throws exception { ch.pipeline() .addlast("ssl", new sslhandler(sslctx.newengine(ch.alloc()))) .addlast("http", new httpclientcodec(4096, 8192, 8192, true, true)) .addlast("simple", new simplechannelinboundhandler<httpobject>() { @override public void channelactive(channelhandlercontext ctx) throws exception { // ctx.writeandflush(createreq()); } @override protected void channelread0(channelhandlercontext ctx, httpobject msg) throws exception { system.out.println(msg); // ctx.writeandflush(createreq()); } }) .addlast(new logginghandler()); } }); channel channel = cb.connect().sync().channel(); channel.write(createreq()); thread.sleep(1000l); channel.write(createreq()); } private static defaultfullhttprequest createreq() throws urisyntaxexception { defaultfullhttprequest requestcopy = new defaultfullhttprequest(httpversion.http_1_1, httpmethod.get, new uri("/").toasciistring()); httpheaders headerscopy = requestcopy.headers(); headerscopy.set(httpheadernames.host, host); headerscopy.set(httpheadernames.connection, httpheadervalues.keep_alive); return requestcopy; } }
at end of main method send 2 http requests 1 second delay. server responds on first request, not on second...
i've enabled detail logging:
fine: -dio.netty.recycler.maxcapacity.maxcapacity: 262144 jan 28, 2016 4:32:30 pm io.netty.handler.logging.logginghandler write fine: [id: 0x2baa7120, /172.21.222.178:32972 => google.com/173.194.220.138:443] write, defaultfullhttprequest(decoderesult: success, version: http/1.1, content: unpooledunsafeheapbytebuf(ridx: 0, widx: 0, cap: 0)) / http/1.1 host: google.com connection: keep-alive, 0b jan 28, 2016 4:32:30 pm io.netty.handler.ssl.util.insecuretrustmanagerfactory$1 checkservertrusted fine: accepting server certificate: cn=*.google.com, o=google inc, l=mountain view, st=california, c=us jan 28, 2016 4:32:30 pm io.netty.handler.ssl.ciphersuiteconverter cachefromopenssl fine: cipher suite mapping: tls_ecdhe_rsa_with_aes_128_gcm_sha256 => ecdhe-rsa-aes128-gcm-sha256 jan 28, 2016 4:32:30 pm io.netty.handler.ssl.ciphersuiteconverter cachefromopenssl fine: cipher suite mapping: ssl_ecdhe_rsa_with_aes_128_gcm_sha256 => ecdhe-rsa-aes128-gcm-sha256 jan 28, 2016 4:32:30 pm io.netty.handler.ssl.sslhandler sethandshakesuccess fine: [id: 0x2baa7120, /172.21.222.178:32972 => google.com/173.194.220.138:443] handshaken: tls_ecdhe_rsa_with_aes_128_gcm_sha256 jan 28, 2016 4:32:30 pm io.netty.handler.logging.logginghandler usereventtriggered fine: [id: 0x2baa7120, /172.21.222.178:32972 => google.com/173.194.220.138:443] user_event: sslhandshakecompletionevent(success) defaulthttpresponse(decoderesult: success, version: http/1.1) http/1.1 302 found location: https://ipv4.google.com/sorry/indexredirect?continue=https://google.com/&q=cgmsbfuxuysy7rcotquigqdxp4nlp1t70jloofxaotbiyimcgkkrqxe date: thu, 28 jan 2016 13:32:31 gmt pragma: no-cache expires: fri, 01 jan 1990 00:00:00 gmt cache-control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 content-type: text/html; charset=utf-8 server: http server (unknown) content-length: 331 x-xss-protection: 1; mode=block x-frame-options: sameorigin alternate-protocol: 443:quic,p=1 alt-svc: quic=":443"; ma=604800; v="30,29,28,27,26,25" defaultlasthttpcontent(data: slicedabstractbytebuf(ridx: 0, widx: 331, cap: 331/331, unwrapped: pooledunsafedirectbytebuf(ridx: 913, widx: 913, cap: 942)), decoderresult: success) jan 28, 2016 4:32:32 pm io.netty.handler.logging.logginghandler write fine: [id: 0x2baa7120, /172.21.222.178:32972 => google.com/173.194.220.138:443] write, defaultfullhttprequest(decoderesult: success, version: http/1.1, content: unpooledunsafeheapbytebuf(ridx: 0, widx: 0, cap: 0)) / http/1.1 host: google.com connection: keep-alive, 0b jan 28, 2016 4:36:31 pm io.netty.handler.logging.logginghandler channelinactive fine: [id: 0x2baa7120, /172.21.222.178:32972 :> google.com/173.194.220.138:443] inactive jan 28, 2016 4:36:31 pm io.netty.handler.logging.logginghandler exceptioncaught fine: [id: 0x2baa7120, /172.21.222.178:32972 :> google.com/173.194.220.138:443] exception: io.netty.handler.codec.prematurechannelclosureexception: channel gone inactive 1 missing response(s) io.netty.handler.codec.prematurechannelclosureexception: channel gone inactive 1 missing response(s) @ io.netty.handler.codec.http.httpclientcodec$decoder.channelinactive(httpclientcodec.java:228) @ io.netty.channel.combinedchannelduplexhandler.channelinactive(combinedchannelduplexhandler.java:213) @ io.netty.channel.channelhandlerinvokerutil.invokechannelinactivenow(channelhandlerinvokerutil.java:56) @ io.netty.channel.defaultchannelhandlerinvoker.invokechannelinactive(defaultchannelhandlerinvoker.java:93) @ io.netty.channel.abstractchannelhandlercontext.firechannelinactive(abstractchannelhandlercontext.java:133) @ io.netty.handler.codec.bytetomessagedecoder.channelinactive(bytetomessagedecoder.java:332) @ io.netty.handler.ssl.sslhandler.channelinactive(sslhandler.java:724) @ io.netty.channel.channelhandlerinvokerutil.invokechannelinactivenow(channelhandlerinvokerutil.java:56) @ io.netty.channel.defaultchannelhandlerinvoker.invokechannelinactive(defaultchannelhandlerinvoker.java:93) @ io.netty.channel.abstractchannelhandlercontext.firechannelinactive(abstractchannelhandlercontext.java:133) @ io.netty.channel.defaultchannelpipeline.firechannelinactive(defaultchannelpipeline.java:895) @ io.netty.channel.abstractchannel$abstractunsafe$7.run(abstractchannel.java:719) @ io.netty.util.concurrent.singlethreadeventexecutor.runalltasks(singlethreadeventexecutor.java:339) @ io.netty.channel.nio.nioeventloop.run(nioeventloop.java:356) @ io.netty.util.concurrent.singlethreadeventexecutor$5.run(singlethreadeventexecutor.java:742) @ io.netty.util.concurrent.defaultthreadfactory$defaultrunnabledecorator.run(defaultthreadfactory.java:137) @ java.lang.thread.run(thread.java:745)
as can see, server replied on first request , ignored second request.
but if remove:
channel.write(createreq()); thread.sleep(1000l); channel.write(createreq());
and uncomment code inside channelinitializer:
.addlast("simple", new simplechannelinboundhandler<httpobject>() { @override public void channelactive(channelhandlercontext ctx) throws exception { ctx.writeandflush(createreq()); } @override protected void channelread0(channelhandlercontext ctx, httpobject msg) throws exception { system.out.println(msg); ctx.writeandflush(createreq()); } })
everything work flying colours , i've got expected:
defaulthttpresponse(decoderesult: success, version: http/1.1) http/1.1 302 found location: https://ipv4.google.com/sorry/indexredirect?continue=https://google.com/&q=cgmsbfuxuysyprsotquigqdxp4nlfkyg4_x9zrf5oyzq5oluqegr-54 date: thu, 28 jan 2016 13:39:50 gmt pragma: no-cache expires: fri, 01 jan 1990 00:00:00 gmt cache-control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 content-type: text/html; charset=utf-8 server: http server (unknown) content-length: 331 x-xss-protection: 1; mode=block x-frame-options: sameorigin alternate-protocol: 443:quic,p=1 alt-svc: quic=":443"; ma=604800; v="30,29,28,27,26,25" defaultlasthttpcontent(data: slicedabstractbytebuf(ridx: 0, widx: 331, cap: 331/331, unwrapped: pooledunsafedirectbytebuf(ridx: 913, widx: 913, cap: 942)), decoderresult: success) defaulthttpresponse(decoderesult: success, version: http/1.1) http/1.1 302 found location: https://ipv4.google.com/sorry/indexredirect?continue=https://google.com/&q=cgmsbfuxuysyprsotquigqdxp4nlfkyg4_x9zrf5oyzq5oluqegr-54 date: thu, 28 jan 2016 13:39:51 gmt pragma: no-cache expires: fri, 01 jan 1990 00:00:00 gmt cache-control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 content-type: text/html; charset=utf-8 server: http server (unknown) content-length: 331 x-xss-protection: 1; mode=block x-frame-options: sameorigin alternate-protocol: 443:quic,p=1 alt-svc: quic=":443"; ma=604800; v="30,29,28,27,26,25" defaultlasthttpcontent(data: slicedabstractbytebuf(ridx: 0, widx: 331, cap: 331/331, unwrapped: pooledunsafedirectbytebuf(ridx: 913, widx: 913, cap: 942)), decoderresult: success)
what's problem? can't write channel outside netty's callback methods?
when using netty,it important make sure every call write()
followed call flush()
, when write channel, write without flushing, causing data stay in memory of program, , not being send out.
change call write()
writeandflush()
.
Comments
Post a Comment