Tunnel是什么?Tunnel存在的意义就是利用http协议来传输非http协议的内容。使用fiddler4抓包时,经常会看到类似Tunnel的包。打开后你会发现没有标准的http协议模式,没有http头,包体也和HTTP协议包体不同。Tunnel可以作为服务端和客户端的双向通信,解决了http1.1中服务端不能主动向客户端发送信息的问题。Springboot中如何实现Tunnel?Springboot提供了HttpTunnelServer来提供Tunnel等功能。我们可以先看看它的源码publicHttpTunnelServer(TargetServerConnectionserverConnection){Assert.notNull(serverConnection,"ServerConnectionmustnotbenull");this.serverConnection=serverConnection;}从构造方法可以看出,传入了一个TargetServerConnection实例,TargetServerConnection是一个函数式接口。@FunctionalInterfacepublicinterfaceTargetServerConnection{ByteChannelopen(inttimeout)throwsIOException;}在源码中,有一个该接口的现类SocketTargetServerConnectionpublicclassSocketTargetServerConnectionimplementsTargetServerConnection{publicSocketTargetServerConnection(PortProviderportProvider){Assert.notNull(portProvider,"PortProvidermustnotbe无效的”);this.portProvider=portProvider;}@OverridepublicByteChannelopen(intsocketTimeout)throwsIOException{SocketAddress地址=newInetSocketAddress(this.portProvider.getPort());logger.trace(LogMessage.format("在%s上打开到目标服务器的隧道连接",address));SocketChannel通道=SocketChannel.open(地址);channel.socket().setSoTimeout(socketTimeout);返回新的TimeoutAwareChannel(通道);}......}//SocketTargetServerConnection的构造函数传入函数接口PortProvider,//是一个函数接口@FunctionalInterfacepub来获取端口licinterfacePortProvider{/***返回端口号。*@returntheportnumber*/intgetPort();}显然,这个方法是为了Tunnel与其他服务交互而提供的。SocketTargetServerConnection的open函数是Openaport与远程端口交互Springboot自带的测试代码中@BeanDispatcherFilterfilter(AnnotationConfigServletWebServerApplicationContextcontext){TargetServerConnectionconnection=newSocketTargetServerConnection(()->context.getWebServer().getPort());HttpTunnelServerserver=newHttpTunnelServer//(连接);对端端口,定义一个HttpTunnelServerHandlerMappermapper=newUrlHandlerMapper("/httptunnel",newHttpTunnelServerHandler(server));//创建处理程序Collection
