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

来源:互联网 发布:淘宝上的日本代购 编辑:程序博客网 时间:2024/06/07 00:58

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

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

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


import sysimport signalimport urlparseimport geventfrom gevent.server import StreamServerfrom gevent.socket import create_connection, gethostbynameclass 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), portdef 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()