gevent实现基于端口转发的http代理服务器

在gevent的例子里有一个端口转发的例子,不过这个例子的地址都是直接指定的,比如运行:

portforwarder.py 127.0.0.1:8080  www.baidu.com:80 

通过修改下,我们可以实现动态的端口转发,从请求头分析出目标地址,然后动态建立端口转发,代码如下:


import sys
import signal
import urlparse
import gevent
from gevent.server import StreamServer
from gevent.socket import create_connection, gethostbyname


class ProxyServer(StreamServer):
    def __init__(self, listener, **kwargs):
        StreamServer.__init__(self, listener, **kwargs)

    def handle(self, client, address):
        log('%s:%s accepted', *address[:2])
        try:
            line1 = ''
            while True:
                _data = client.recv(1)
                line1 += _data
                if not _data or _data == '\n':
                    break
            if line1:
                print (line1)
                remote_path = parse_address(line1.split()[1])
                remote = create_connection(remote_path)
                remote.sendall(line1)
                source_address = '%s:%s' % client.getpeername()[:2]
                dest_address = '%s:%s' % remote.getpeername()[:2]
                log("Starting port forwarder %s -> %s",source_address,dest_address)                 
                gevent.spawn(forward, client, remote)
                gevent.spawn(forward, remote, client) 
            
            else:
                client.close()
                return  

            
        except IOError, ex:
            log('failed : %s', ex)
            import traceback
            traceback.print_exc()
            return


    def close(self):
        if self.closed:
            sys.exit('Multiple exit signals received - aborting.')
        else:
            log('Closing listener socket')
            StreamServer.close(self)


def forward(source, dest):
    source_address = '%s:%s' % source.getpeername()[:2]
    dest_address = '%s:%s' % dest.getpeername()[:2]
    try:
        while True:
            data = source.recv(1024)
            if not data:
                break
            log('%s->%s: %r bytes', source_address, dest_address, len(data))
            dest.sendall(data)
    finally:
        source.close()
        dest.close()


def parse_address(address):
    try:
        urls = urlparse.urlparse(address)
        address = urls.netloc or urls.path
        _addr = address.split(':')
        hostname, port = len(_addr) == 2 and  _addr or (_addr[0],80)
        port = int(port)
    except ValueError:
        sys.exit('Expected HOST:PORT: %r' % address)
    return gethostbyname(hostname), port

def main():
    server = ProxyServer(('0.0.0.0',8087))
    log('Starting proxy server %s:%s', *(server.address[:2]))
    gevent.signal(signal.SIGTERM, server.close)
    gevent.signal(signal.SIGINT, server.close)
    server.start()
    gevent.run()


def log(message, *args):
    message = message % args
    sys.stderr.write(message + '\n')


if __name__ == '__main__':
    main()


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值