- 浏览: 786731 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
萨琳娜啊:
Java读源码之Netty深入剖析网盘地址:https://p ...
Netty源码学习-FileRegion -
飞天奔月:
写得有趣 ^_^
那一年你定义了一个接口 -
GoldRoger:
第二个方法很好
java-判断一个自然数是否是某个数的平方。当然不能使用开方运算 -
bylijinnan:
<script>alert("close ...
自己动手实现Java Validation -
paul920531:
39行有个bug:"int j=new Random ...
java-蓄水池抽样-要求从N个元素中随机的抽取k个元素,其中N无法确定
Netty关于HTTP tunnel的说明:
http://docs.jboss.org/netty/3.2/api/org/jboss/netty/channel/socket/http/package-summary.html#package_description
这个说明有点太简略了
一个完整的例子在这里:
https://github.com/bylijinnan/nettyLearn/tree/master/ljn-netty3-httptunnel
示例里的具体流程是这样:
1.web工程(以下称为HttpServer)启动时,注册HttpTunnelingServlet并通过Spring启动Server(以下称为ServerNetty):
//web.xml <servlet> <servlet-name>NettyTunnelingServlet</servlet-name> <servlet-class>org.jboss.netty.channel.socket.http.HttpTunnelingServlet</servlet-class> <init-param> <param-name>endpoint</param-name> <param-value>local:myLocalServer</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>NettyTunnelingServlet</servlet-name> <url-pattern>/netty-tunnel</url-pattern> </servlet-mapping> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> //applicationContext.xml,bean初始化完成后,调用start方法 <bean id="com.ljn.netty3.tunnelserver.LocalEchoServerRegistration" class="com.ljn.netty3.tunnelserver.LocalEchoServerRegistration" init-method="start" destroy-method="stop" /> //LocalEchoServerRegistration.java的start方法启动ServerNetty(这里ServerNetty的作用是echo): public class LocalEchoServerRegistration { public void start() { ServerBootstrap serverBootstrap = new ServerBootstrap(factory); EchoServerHandler handler = new EchoServerHandler(); serverBootstrap.getPipeline().addLast("handler", handler); serverChannel = serverBootstrap.bind(new LocalAddress("myLocalServer")); } }
2.ClientNetty向HttpServer发起一个HTTP连接(URL为http://localhost:8088/netty3tunnelserver/netty-tunnel)
该连接被HttpServer端的HttpTunnelingServlet捕获
3.HttpTunnelingServlet做以下两个操作:
a.开启一个Client并连接到ServerNetty,把HttpRequest的数据发给ServerNetty:
b.读取ServerNetty的响应数据,通过HttpResponse转发给ClientNetty
HttpTunnelingServlet相当于一个“代理”:
对于ClientNetty来说,它是“Server”;对于ServerNetty来说,它是“Client”:
class HttpTunnelingServlet ...{ protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { //只支持POST if (!"POST".equalsIgnoreCase(req.getMethod())) { if (logger.isWarnEnabled()) { logger.warn("Unallowed method: " + req.getMethod()); } res.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); return; } final ChannelPipeline pipeline = Channels.pipeline(); final ServletOutputStream out = res.getOutputStream(); //messageReceived时,把从“ServerNetty”中接收到的数据写到HttpResponse final OutboundConnectionHandler handler = new OutboundConnectionHandler(out); pipeline.addLast("handler", handler); Channel channel = channelFactory.newChannel(pipeline); //向“ServerNetty”发起连接 ChannelFuture future = channel.connect(remoteAddress).awaitUninterruptibly(); ChannelFuture lastWriteFuture = null; try { res.setStatus(HttpServletResponse.SC_OK); res.setHeader(HttpHeaders.Names.CONTENT_TYPE, "application/octet-stream"); res.setHeader(HttpHeaders.Names.CONTENT_TRANSFER_ENCODING, HttpHeaders.Values.BINARY); //先发送响应头 out.flush(); /*从HttpRequest中读取数据并发送给“ServerNetty” 不理解为什么要用PushbackInputStream(通常用在“parse data”:先读取InputStream前面一些字节 来决定如何解析这个InputStream) */ PushbackInputStream in = new PushbackInputStream(req.getInputStream()); while (channel.isConnected()) { ChannelBuffer buffer; try { buffer = read(in); } catch (EOFException e) { break; } if (buffer == null) { break; } lastWriteFuture = channel.write(buffer); } } } }
回过头来看看ClientNetty如何发HttpRequest:
class HttpTunnelingClientExample ...{ ClientBootstrap b = new ClientBootstrap( new HttpTunnelingClientSocketChannelFactory( new OioClientSocketChannelFactory(Executors.newCachedThreadPool()))); b.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline( new StringDecoder(), new StringEncoder(), new LoggingHandler(InternalLogLevel.INFO)); } }); // Set additional options required by the HTTP tunneling transport. b.setOption("serverName", uri.getHost()); b.setOption("serverPath", uri.getRawPath()); // Make the connection attempt. ChannelFuture channelFuture = b.connect( new InetSocketAddress(uri.getHost(), uri.getPort())); channelFuture.awaitUninterruptibly(); // Read commands from the stdin. System.out.println("Enter text ('quit' to exit)"); ChannelFuture lastWriteFuture = null; BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); for (; ;) { String line = in.readLine(); if (line == null || "quit".equalsIgnoreCase(line)) { break; } // Sends the received line to the server. lastWriteFuture = channelFuture.getChannel().write(line); } }
ClientNetty做的事情很简单:启动ClientBootstrap并connect,然后读取System.in的输入并发送
ClientNetty只是一行一行地发送字符串,那是如何发送HttpRequest呢(POST)?
答案在HttpTunnelingClientSocketChannel
ClientNetty在connect时,触发CONNECTED的ChannelStateEvent并被HttpTunnelingClientSocketPipelineSink捕获,
最后调用HttpTunnelingClientSocketChannel的connectReal方法。在connect成功后,发送HttpRequest:
void connectReal(final SocketAddress remoteAddress, final ChannelFuture future) { final String serverName = config.getServerName(); final int serverPort = ((InetSocketAddress) remoteAddress).getPort(); final String serverPath = config.getServerPath(); if (f.isSuccess()) { ...something about SSL // Send the HTTP request. final HttpRequest req = new DefaultHttpRequest( HttpVersion.HTTP_1_1, HttpMethod.POST, serverPath); if (serverName != null) { req.setHeader(HttpHeaders.Names.HOST, serverName); } req.setHeader(HttpHeaders.Names.CONTENT_TYPE, "application/octet-stream"); req.setHeader(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED); req.setHeader(HttpHeaders.Names.CONTENT_TRANSFER_ENCODING, HttpHeaders.Values.BINARY); req.setHeader(HttpHeaders.Names.USER_AGENT, HttpTunnelingClientSocketChannel.class.getName()); realChannel.write(req); requestHeaderWritten = true; future.setSuccess(); fireChannelConnected(virtualChannel, remoteAddress); } }
可以看到,发送的HttpRequest是POST,且采用chunk方式
它与一般浏览器的HttpRequest还不太一样,浏览器把请求发过去就结束了
但它会一直等用户输入,直到用户输入“quit”退出才断开http连接
因此,在NettyClient里通过System.in输入的每一行,都是一个chunk也就不奇怪了:
//HttpTunnelingClientSocketChannel的writeReal方法 void writeReal(final ChannelBuffer a, final ChannelFuture future) { final int size = a.readableBytes(); final ChannelFuture f; if (size == 0) { f = realChannel.write(ChannelBuffers.EMPTY_BUFFER); } else { f = realChannel.write(new DefaultHttpChunk(a)); } ... }
参考:
PushbackInputStream:http://tutorials.jenkov.com/java-io/pushbackinputstream.html
HTTP tunnel的含义:http://www.360doc.com/content/11/0512/21/4478545_116303972.shtml
发表评论
-
TCP的TIME-WAIT
2014-04-23 16:35 1197原文连接:http://vincent.bernat.im/e ... -
《TCPIP详解卷1》学习-拥塞避免
2014-01-15 15:16 159拥塞避免算法、 ... -
Netty源码学习-FileRegion
2013-12-31 17:17 5654今天看org.jboss.netty.example.http ... -
Netty源码学习-HttpChunkAggregator-HttpRequestEncoder-HttpResponseDecoder
2013-12-27 16:10 4086今天看Netty如何实现一个Http Server org.j ... -
Netty源码学习-ReadTimeoutHandler
2013-12-26 17:53 3836ReadTimeoutHandler的实现思 ... -
Netty学习笔记
2013-12-25 18:39 1488本文是阅读以下两篇文章时: http://seeallhear ... -
Netty源码学习-ChannelHandler
2013-12-25 18:12 1634一般来说,“有状态”的ChannelHandler不应 ... -
Netty源码学习-ServerBootstrap启动及事件处理过程
2013-12-19 20:11 10763Netty是采用了Reactor模式的多线程版本,建议先看下面 ... -
Netty源码学习-Java-NIO-Reactor
2013-12-19 18:21 4891Netty里面采用了NIO-based Reactor Pat ... -
Netty源码学习-ReplayingDecoder
2013-12-13 20:21 4265ReplayingDecoder是FrameDecoder的子 ... -
Netty源码学习-DefaultChannelPipeline2
2013-12-11 15:47 1284Netty3的API http://docs.jboss.or ... -
Netty源码学习-CompositeChannelBuffer
2013-12-06 15:54 2761CompositeChannelBuffer体现了Netty的 ... -
Netty源码学习-DelimiterBasedFrameDecoder
2013-12-05 18:36 9559看DelimiterBasedFrameDecoder的AP ... -
Netty源码学习-ObjectEncoder和ObjectDecoder
2013-12-05 16:06 5004Netty中传递对象的思路很直观: Netty中数据的传递是基 ... -
Netty源码学习-LengthFieldBasedFrameDecoder
2013-12-05 15:20 7306先看看LengthFieldBasedFrameDecoder ... -
Netty源码学习-FrameDecoder
2013-11-28 18:38 3929Netty 3.x的user guide里FrameDecod ... -
Netty源码学习-DefaultChannelPipeline
2013-11-27 17:00 2238package com.ljn.channel; /** ...
相关推荐
赠送jar包:netty-codec-http2-4.1.74.Final.jar; 赠送原API文档:netty-codec-http2-4.1.74.Final-javadoc.jar; 赠送源代码:netty-codec-http2-4.1.74.Final-sources.jar; 赠送Maven依赖信息文件:netty-codec-...
赠送jar包:netty-codec-http-4.1.27.Final.jar; 赠送原API文档:netty-codec-http-4.1.27.Final-javadoc.jar; 赠送源代码:netty-codec-http-4.1.27.Final-sources.jar; 赠送Maven依赖信息文件:netty-codec-...
赠送jar包:netty-codec-http2-4.1.73.Final.jar; 赠送原API文档:netty-codec-http2-4.1.73.Final-javadoc.jar; 赠送源代码:netty-codec-http2-4.1.73.Final-sources.jar; 赠送Maven依赖信息文件:netty-codec-...
赠送jar包:netty-codec-http-4.1.11.Final.jar; 赠送原API文档:netty-codec-http-4.1.11.Final-javadoc.jar; 赠送源代码:netty-codec-http-4.1.11.Final-sources.jar; 赠送Maven依赖信息文件:netty-codec-...
赠送jar包:netty-codec-http-4.1.68.Final.jar; 赠送原API文档:netty-codec-http-4.1.68.Final-javadoc.jar; 赠送源代码:netty-codec-http-4.1.68.Final-sources.jar; 赠送Maven依赖信息文件:netty-codec-...
赠送jar包:netty-codec-http-4.1.73.Final.jar; 赠送原API文档:netty-codec-http-4.1.73.Final-javadoc.jar; 赠送源代码:netty-codec-http-4.1.73.Final-sources.jar; 赠送Maven依赖信息文件:netty-codec-...
赠送jar包:reactor-netty-http-1.0.11.jar; 赠送原API文档:reactor-netty-http-1.0.11-javadoc.jar; 赠送源代码:reactor-netty-http-1.0.11-sources.jar; 赠送Maven依赖信息文件:reactor-netty-...
赠送jar包:netty-codec-http-4.1.74.Final.jar; 赠送原API文档:netty-codec-http-4.1.74.Final-javadoc.jar; 赠送源代码:netty-codec-http-4.1.74.Final-sources.jar; 赠送Maven依赖信息文件:netty-codec-...
赠送jar包:reactor-netty-http-1.0.15.jar; 赠送原API文档:reactor-netty-http-1.0.15-javadoc.jar; 赠送源代码:reactor-netty-http-1.0.15-sources.jar; 赠送Maven依赖信息文件:reactor-netty-...
赠送jar包:netty-codec-http2-4.1.68.Final.jar; 赠送原API文档:netty-codec-http2-4.1.68.Final-javadoc.jar; 赠送源代码:netty-codec-http2-4.1.68.Final-sources.jar; 赠送Maven依赖信息文件:netty-codec-...
赠送jar包:netty-codec-http-4.1.11.Final.jar; 赠送原API文档:netty-codec-http-4.1.11.Final-javadoc.jar; 赠送源代码:netty-codec-http-4.1.11.Final-sources.jar; 赠送Maven依赖信息文件:netty-codec-...
赠送jar包:netty-codec-mqtt-4.1.73.Final.jar; 赠送原API文档:netty-codec-mqtt-4.1.73.Final-javadoc.jar; 赠送源代码:netty-codec-mqtt-4.1.73.Final-sources.jar; 赠送Maven依赖信息文件:netty-codec-...
赠送jar包:netty-transport-native-unix-common-4.1.73.Final.jar; 赠送原API文档:netty-transport-native-unix-common-4.1.73.Final-javadoc.jar; 赠送源代码:netty-transport-native-unix-common-4.1.73....
赠送jar包:netty-transport-classes-epoll-4.1.73.Final.jar; 赠送原API文档:netty-transport-classes-epoll-4.1.73.Final-javadoc.jar; 赠送源代码:netty-transport-classes-epoll-4.1.73.Final-sources.jar;...
赠送jar包:netty-resolver-dns-4.1.65.Final.jar; 赠送原API文档:netty-resolver-dns-4.1.65.Final-javadoc.jar; 赠送源代码:netty-resolver-dns-4.1.65.Final-sources.jar; 赠送Maven依赖信息文件:netty-...
netty-codec-http-4.1.32.Final-sources.jar netty-codec-http-4.1.32.Final.jar netty-codec-http2-4.1.32.Final-sources.jar netty-codec-http2-4.1.32.Final.jar netty-codec-memcache-4.1.32.Final-sources.jar ...
Netty (netty-netty-4.1.77.Final.tar.gz)是一个 NIO 客户端服务器框架,可以快速轻松地开发协议服务器和客户端等网络应用程序。它极大地简化和流线了网络编程,例如 TCP 和 UDP 套接字服务器。 “快速和简单”并...
赠送jar包:netty-codec-haproxy-4.1.74.Final.jar; 赠送原API文档:netty-codec-haproxy-4.1.74.Final-javadoc.jar; 赠送源代码:netty-codec-haproxy-4.1.74.Final-sources.jar; 赠送Maven依赖信息文件:netty-...
赠送jar包:netty-codec-dns-4.1.65.Final.jar; 赠送原API文档:netty-codec-dns-4.1.65.Final-javadoc.jar; 赠送源代码:netty-codec-dns-4.1.65.Final-sources.jar; 赠送Maven依赖信息文件:netty-codec-dns-...
赠送jar包:netty-transport-classes-epoll-4.1.74.Final.jar; 赠送原API文档:netty-transport-classes-epoll-4.1.74.Final-javadoc.jar; 赠送源代码:netty-transport-classes-epoll-4.1.74.Final-sources.jar;...