使用Netty代理,提高工作效率

原创 2016年06月05日 19:03:13


最近工作中负责银行监管系统的对接。在申请银行测试环境的时候,流程复杂繁琐,耗费时间长。  我负责开发和测试银行的接口,但是开发阶段必须连接银行环境,但是银行环境又不能直接到本地。如果指定了本地端口,等测试验收时环境又不一样。银行回复给我们消息时服务地址又要改变,申请银行更改端口流程又负责。所以想在开发阶段和测试验收阶段使用同一个服务端,我采用了代理的方式。



当在本地local 端想通过中间proxy 来发送和接收请求到银行remote端,就可以使用代理。 就像我们平时使用的vpn一样,连接到vpn服务器上,然后通vpn服务器来转发和接收你的请求。

在netty的example中就有简单的例子。我的例子就是从里面改变而来。


ProxyConfig.properties 配置端口:

localIp=221.228.241.106
localPort=8443
    
ProxyIp  =192.168.2.13
ProxyPort =54951

remoteIp=202.108.57.118
remotePort=35053
HexDumpProxy.java  代理服务器端:

public final class HexDumpProxy
{
	private static Logger logger = LoggerFactory.getLogger(HexDumpProxy.class);
	
	//中间IP和端口
	static final String PROXY_IP =ProxyConfig.getInstance().getProxyIp();
	static final int PROXY_PORT = Integer.parseInt(ProxyConfig.getInstance().getProxyPort());

	public static void main(String[] args) throws Exception
	{
		
        logger.info("**********************启动代理 ********************** Ip:{} port:{}",PROXY_IP,PROXY_PORT);
		EventLoopGroup bossGroup = new NioEventLoopGroup(1);
		EventLoopGroup workerGroup = new NioEventLoopGroup();
		try
		{   //这里启动代理服务器端,用来接收local端和remote端的消息
			//把从来自local端的消息转发到remote端
			//把从来自remote端的消息转发到local端
			ServerBootstrap b = new ServerBootstrap();
			b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
			.handler(new LoggingHandler(LogLevel.INFO))
			.childHandler(new HexDumpProxyInitializer())
			.childOption(ChannelOption.AUTO_READ, false)
			.bind(new InetSocketAddress(PROXY_IP, PROXY_PORT))  //代理端口
			.sync().channel().closeFuture().sync();
		}
		finally
		{
			bossGroup.shutdownGracefully();
			workerGroup.shutdownGracefully();
		}
	}
}
HexDumpProxyInitializer.java 文件 主要处理proxy服务器的handler

public class HexDumpProxyInitializer extends ChannelInitializer<SocketChannel>
{

	public HexDumpProxyInitializer()
	{
	}
	@Override
	public void initChannel(SocketChannel ch)
	{
		ch.pipeline().addLast(new LoggingHandler(LogLevel.INFO),new HexDumpProxyFrontendHandler());
	}
}


在HexDumpProxy 中主要关注HexDumpProxyFrontendHandler该类主要处理连接事件和数据的读取写入事件。

public class HexDumpProxyFrontendHandler extends ChannelInboundHandlerAdapter {

	private static Logger logger =LoggerFactory.getLogger(HexDumpProxyFrontendHandler.class);

    
    //写入银行的通道
    private volatile Channel outbound2BankChannel;

   
    public HexDumpProxyFrontendHandler() {
     
    }
    //当local或者remote与proxy连接时,proxy会发起到local或者remote端的连接
    @Override
    public void channelActive(ChannelHandlerContext ctx) {

        final Channel inboundChannel = ctx.channel();
        InetSocketAddress address = (InetSocketAddress)inboundChannel.remoteAddress();
        logger.info("============连接代理成功==================");
        logger.info("channelActive  IP:{} port:{}",address.getHostString(),address.getPort());
    	// Start the connection attempt.
    	Bootstrap b = new Bootstrap();
    	b.group(inboundChannel.eventLoop())
    	.channel(ctx.channel().getClass())
    	.option(ChannelOption.AUTO_READ, true)
    	.handler(new ChannelInitializer<SocketChannel>() {
            @Override
            public void initChannel(SocketChannel ch) throws Exception {
                ChannelPipeline p = ch.pipeline();
               
                //p.addLast(new LoggingHandler(LogLevel.INFO));
                p.addLast(new HexDumpProxyBackendHandler(inboundChannel),new LoggingHandler(LogLevel.INFO));
            }
        });
    	ChannelFuture f = b.connect(ProxyConfig.getInstance().getRemoteIp(), Integer.parseInt(ProxyConfig.getInstance().getRemotePort()));
    	outbound2BankChannel = f.channel();
    
    	f.addListener(new ChannelFutureListener() {
    		@Override
    		public void operationComplete(ChannelFuture future) {
    			if (future.isSuccess()) {
    				// connection complete start to read first data
    				inboundChannel.read();
    			} else {
    				// Close the connection if the connection attempt has failed.
    				inboundChannel.close();
    			}
    		}
    	});
    

    }
   //当从local或者remote写入到proxy时,proxy把读取到的数据直接写入到local或者remote端
    @Override
    public void channelRead(final ChannelHandlerContext ctx, Object msg) {
    	logger.debug("==============向目标服务器写入数据========================");
    	InetSocketAddress fromAddress = (InetSocketAddress)ctx.channel().remoteAddress();
    	logger.debug("数据来自:{}",fromAddress.getHostName());
    	
    	if (outbound2BankChannel.isActive()) {
    		outbound2BankChannel.writeAndFlush(msg).addListener(new ChannelFutureListener() {
    			@Override
    			public void operationComplete(ChannelFuture future) {
    				if (future.isSuccess()) {
    					InetSocketAddress toAddress = (InetSocketAddress)outbound2BankChannel.remoteAddress();
    					logger.debug("数据发往:{}",toAddress.getHostName());
    					// was able to flush out data, start to read the next chunk
    					ctx.channel().read();
    				} else {
    					future.channel().close();
    				}
    			}
    		});
    	}


    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
    	Channel ch = ctx.channel();
    	InetSocketAddress address = (InetSocketAddress)ch.remoteAddress();
    	logger.info("=============与代理服务器端口断开连接==================");
    	logger.info("channelInactive  IP:{} port:{}",address.getHostString(),address.getPort());
    	
    	if (outbound2BankChannel != null) {
    		closeOnFlush(outbound2BankChannel);
    	}

    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
    	Channel ch = ctx.channel();
    	InetSocketAddress address = (InetSocketAddress)ch.remoteAddress();
    	logger.info("=============与代理服务器端口端口连接==================");
    	logger.info("exceptionCaught  IP:{} port:{}",address.getHostString(),address.getPort());
        cause.printStackTrace();
        closeOnFlush(ctx.channel());
    }

    /**
     * Closes the specified channel after all queued write requests are flushed.
     */
    static void closeOnFlush(Channel ch) {
        if (ch.isActive()) {
              ch.flush();
        }
    }
}

HexDumpProxyBackendHandler.java 文件主要负责数据的搬运。

public class HexDumpProxyBackendHandler extends ChannelInboundHandlerAdapter {

	private static Logger logger =LoggerFactory.getLogger(HexDumpProxyBackendHandler.class);
 

	 //写入本地的通道
    private volatile Channel outbound2LocalChannel;
    
    
    public HexDumpProxyBackendHandler(Channel outbound2LocalChannel) 
    {
       this.outbound2LocalChannel =outbound2LocalChannel;
    }
   //当proxy与local或者remote连接时,开始从proxy中读取数据
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
    	final Channel inboundChannel = ctx.channel();
    
    	InetSocketAddress address = (InetSocketAddress)inboundChannel.remoteAddress();
    	logger.info("##################代理连接目标端口成功#######################");
    	logger.info("连接目标端口成功。 ip:{} port:{}",address.getHostName(),address.getPort());
        ctx.read();

    }
    //把proxy中的数据读取,同时把数据写入local或者remote端
    @Override
    public void channelRead(final ChannelHandlerContext ctx, Object msg) {
    	logger.info("##################目标服务器向代理写入数据#######################");
     	InetSocketAddress fromAddress = (InetSocketAddress)ctx.channel().remoteAddress();
    	logger.debug("数据来自:{}",fromAddress.getHostName());
    	outbound2LocalChannel.writeAndFlush(msg).addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) {
                if (future.isSuccess()) {
            		InetSocketAddress toAddress = (InetSocketAddress)outbound2LocalChannel.remoteAddress();
					logger.debug("数据发往:{}",toAddress.getHostName());
                    ctx.channel().read();
                } else {
                    future.channel().close();
                }
            }
        });
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
    	logger.info("############代理和目标地址端口断开连接##############");
        HexDumpProxyFrontendHandler.closeOnFlush(ctx.channel());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
    	logger.info("############代理和目标地址端口断开连接##############");
    	logger.debug("exceptionCaught:{}",cause.getMessage());
        cause.printStackTrace();
        HexDumpProxyFrontendHandler.closeOnFlush(ctx.channel());
    }
}



相关文章推荐

JAVA写HTTP代理服务器(二)-netty实现

接上一篇,因为是用BIO的一个连接一个线程去处理,对于HTTP这种短连接协议来说CPU开销是非常大的,就算加入了线程池也不能完美解决BIO的缺陷,所以可以用NIO进行服务器的优化,NIO基于IO多路复...

使用Netty代理你的请求

本文由 ImportNew - 刘海波 翻译自 mastertheboss。如需转载本文,请先参见文章末尾处的转载要求。 你是否在寻找一个代理来调试你的客户端-服务端的通讯?不需要再寻觅!Net...
  • guomei
  • guomei
  • 2014年03月04日 00:25
  • 942

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

基于netty实现的socks5代理协议

基于netty实现的socks5代理协议socks5协议简介socks5协议是一个标准的代理协议,工作在网络的四层,理论上可以代理任意应用层协议。协议标准RFC1928,用户/密码鉴权标准RFC192...
  • xtuhcy
  • xtuhcy
  • 2016年12月28日 17:34
  • 577

基于netty实现的socks5代理协议

socks5协议 简介 socks5协议是一个标准的代理协议,工作在网络的四层,理论上可以代理任意应用层协议。协议标准RFC1928,用户/密码鉴权标准RFC1929。协议的中文版本可以参...

TCP_proxy tcp代理详解

#coding=utf-8 import sys import socket import threading def server_loop(local_host, local_port...

netty4.0.x源码分析—bootstrap

Bootstrap的意思就是引导,辅助的意思,在编写服务端或客户端程序时,我们都需要先new一个bootstrap,然后基于这个bootstrap调用函数,添加eventloop和handler,可见...

Mina、Netty、Twisted一起学(七):发布/订阅(Publish/Subscribe)

消息传递有很多种方式,请求/响应(Request/Reply)是最常用的。在前面的博文的例子中,很多都是采用请求/响应的方式,当服务器接收到消息后,会立即write回写一条消息到客户端。HTTP协议也...

live555学习笔记-RTSPClient分析

原文地址:http://blog.csdn.net/niu_gao/article/details/6927461 RTSPClient分析 有RTSPServer,当然就...
  • wxh_xdk
  • wxh_xdk
  • 2016年04月21日 16:00
  • 245
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:使用Netty代理,提高工作效率
举报原因:
原因补充:

(最多只允许输入30个字)