当前位置: 首页 > 后端技术 > Java

Netty系列:小白福利!教你做一个简单的代理服务器

时间:2023-04-01 13:24:28 Java

简介爱因斯坦说过:一切伟大都源于简单的细节。Netty为我们提供了如此强大的事件循环和通道。通过有效地利用这些简单的东西,我们可以得到非常强大的应用,比如我们今天要说的代理。Proxy和反向代理相信只要是程序员应该都听说过nginxserver,这个超级优秀的nginx有一个很重要的功能就是做反向代理。那么有朋友要问了,有反向代理就一定有正向代理,那么这两者有什么区别呢?先说正向代理。比如流量明星,最近就受到了很大的打击。虽然被打压了,但星辰就是星辰,普通人是看不到的。如果有人需要和明星对话,他们需要先通过明星的经纪人。一位经纪人将这句话转达给了这位明星。该经纪人是远期代理人。我们通过正向代理访问我们想要访问的对象。那么什么是反向代理呢?比如现在有很多人工智能。如果我们和一个智能机器人A对话,然后A把我们之间的对话转给后面隐藏的那个人,这个人用他的智慧来回答我们的对话,智能机器人A的输出最终实现了人工智能。这个过程称为反向代理。netty实现代理的原理那么在netty中如何实现这个代理服务器呢?首先我们的代理服务器是服务器,所以我们需要在netty中使用ServerBootstrap创建一个服务器:EventLoopGroupbossGroup=newNioEventLoopGroup(1);EventLoopGroupworkerGroup=newNioEventLoopGroup();尝试{ServerBootstrapb=newServerBootstrap();b.组(bossGroup,workerGroup).channel(NioServerSocketChannel.class).handler(newLoggingHandler(LogLevel.INFO)).childHandler(newSimpleDumpProxyInitializer(REMOTE_HOST,REMOTE_PORT)).childOption(ChannelOption.AUTO_READ,false).bind(sync().channel().closeFuture().sync();在这个本地服务器中,我们传入ProxyInitializer。在这个处理程序初始化器中,我们传入了一个自定义处理程序:在自定义处理程序中,我们使用Bootstrap创建一个客户端来连接到要代理的远程服务器。我们把这个客户端的创建放在channelActive方法中://打开出站连接Bootstrapb=newBootstrap();b.group(inboundChannel.eventLoop()).channel(ctx.channel().getClass()).handler(newSimpleDumpProxyOutboundHandler(inboundChannel)).option(ChannelOption.AUTO_READ,false);ChannelFuturef=b.connect(remoteHost,remotePort);然后客户端建立连接后,就可以从inboundChannel中读取数据了:outboundChannel=f.channel();f.addListener(future->{if(future.isSuccess()){//建立连接,读取入站数据inboundChannel.read();}else{//关闭入站通道inboundChannel.close();}});因为是代理服务,inboundChannel读取的数据需要转发给outboundChannel,所以在channelRead中我们需要这样写:publicvoidchannelRead(finalChannelHandlerContextctx,Objectmsg){//inboundChannel中的消息读写到outboundChannelif(outboundChannel.isActive()){outboundChannel.writeAndFlush(msg).addListener((ChannelFutureListener)future->{if(future.isSuccess()){//Flush成功,读取下一条消息ctx.channel().read();}else{future.channel().close();}});}}outboundChannel写入成功后,继续读取inboundChannel同样,对于客户端的outboundChannel,也有一个handler。在这个handler中,我们需要将outboundChannel读取的数据反向写入inboundChannel:publicvoidchannelRead(finalChannelHandlerContextctx,Objectmsg){//将outboundChannel中的数据读取消息并写入inboundChannelinboundChannel.writeAndFlush(msg).addListener((ChannelFutureListener)future->{if(future.isSuccess()){ctx.channel().read();}else{future.channel().close();}});}inboundChannel写入成功后,继续读取outboundChannel。这样一个简单的代理服务器就完成了。实战如果我们把本地的8000端口代理到www.163.com的80端口,会发生什么?运行我们的程序,访问http://localhost:8000,我们会看到如下页面:为什么正常的页面没有我们想象的显示出来?那是因为我们代理后的域名是localhost,不是正常的www.163.com,所以服务器无法识别我们的请求,报错。综上所述,本文简单的在代理服务器之间转发请求无法处理以上场景,那么如何解决以上问题呢?敬请期待我的后续文章!本文示例可参考:learn-netty4本文已收录于http://www.flydean.com/35-netty-simple-proxy/最通俗的解读,最深刻的干货,最简洁的教程,很多你不知道的小技巧等你来发现!欢迎关注我的公众号:《程序那些事儿》,懂技术,更懂你!