非异步
#!/usr/bin/env python # -*- coding: utf-8 -*- import sys import socket import threading import logging import optparse class PipeThread(threading.Thread): def __init__(self, source_fd, target_fd): super(PipeThread, self).__init__() self.logger = logging.getLogger('PipeThread') self.source_fd = source_fd self.target_fd = target_fd self.source_addr = self.source_fd.getpeername() self.target_addr = self.target_fd.getpeername() def run(self): while True: try: data = self.source_fd.recv(4096) if len(data) > 0: self.logger.debug('read %04i from %s:%d', len(data), self.source_addr[0], self.source_addr[1]) sent = self.target_fd.send(data) self.logger.debug('write %04i to %s:%d', sent, self.target_addr[0], self.target_addr[1]) else: break except socket.error: break self.logger.debug('connection %s:%d is closed.', self.source_addr[0], self.source_addr[1]) self.logger.debug('connection %s:%d is closed.', self.target_addr[0], self.target_addr[1]) self.source_fd.close() self.target_fd.close() class Forwarder(object): def __init__(self, ip, port, remoteip, remoteport, backlog=5): self.remoteip = remoteip self.remoteport = remoteport self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.sock.bind((ip, port)) self.sock.listen(backlog) def run(self): while True: client_fd, client_addr = self.sock.accept() target_fd = socket.socket(socket.AF_INET, socket.SOCK_STREAM) target_fd.connect((self.remoteip, self.remoteport)) threads = [ PipeThread(client_fd, target_fd), PipeThread(target_fd, client_fd) ] for t in threads: t.setDaemon(True) t.start() def __del__(self): self.sock.close() def main(): parser = optparse.OptionParser() parser.add_option( '-l', '--local-ip', dest='local_ip', help='Local IP address to bind to') parser.add_option( '-p', '--local-port', type='int', dest='local_port', help='Local port to bind to') parser.add_option( '-r', '--remote-ip', dest='remote_ip', help='Local IP address to bind to') parser.add_option( '-P', '--remote-port', type='int', dest='remote_port', help='Remote port to bind to') parser.add_option( '-v', '--verbose', action='store_true', dest='verbose', help='verbose') opts, args = parser.parse_args() if len(sys.argv) == 1 or len(args) > 0: parser.print_help() exit() if not (opts.local_ip and opts.local_port and opts.remote_ip and opts.remote_port): parser.print_help() exit() if opts.verbose: log_level = logging.DEBUG else: log_level = logging.CRITICAL logging.basicConfig(level=log_level, format='%(name)-11s: %(message)s') forwarder = Forwarder(opts.local_ip, opts.local_port, opts.remote_ip, opts.remote_port) try: forwarder.run() except KeyboardInterrupt: print 'quit' exit() if __name__ == '__main__': main()
异步
#!/usr/bin/env python # -*- coding: utf-8 -*- import sys import socket import asyncore import logging import optparse class Forwarder(asyncore.dispatcher): def __init__(self, ip, port, remoteip, remoteport, backlog=5): asyncore.dispatcher.__init__(self) self.remoteip = remoteip self.remoteport = remoteport self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.set_reuse_addr() self.bind((ip, port)) self.listen(backlog) def handle_accept(self): conn, addr = self.accept() Sender(Receiver(conn), self.remoteip, self.remoteport) class Receiver(asyncore.dispatcher): def __init__(self, conn): asyncore.dispatcher.__init__(self, conn) self.logger = logging.getLogger('Receiver') self.clientaddr, self.clientport = conn.getpeername() self.from_client_buffer = '' self.to_client_buffer = '' self.Sender = None def handle_connect(self): pass def handle_read(self): read = self.recv(4096) if len(read) > 0: self.logger.debug('read %04i --> from %s:%d', len(read), self.clientaddr, self.clientport) self.from_client_buffer += read def writable(self): return len(self.to_client_buffer) > 0 def handle_write(self): sent = self.send(self.to_client_buffer) self.logger.debug('write %04i <-- to %s:%d', sent, self.clientaddr, self.clientport) self.to_client_buffer = self.to_client_buffer[sent:] def handle_close(self): self.close() if self.Sender: self.Sender.close() class Sender(asyncore.dispatcher): def __init__(self, Receiver, remoteaddr, remoteport): asyncore.dispatcher.__init__(self) self.logger = logging.getLogger('Sender') self.remoteaddr = remoteaddr self.remoteport = remoteport self.Receiver = Receiver Receiver.Sender = self self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.connect((remoteaddr, remoteport)) def handle_connect(self): pass def handle_read(self): read = self.recv(4096) if len(read) > 0: self.logger.debug('read <-- %04i from %s:%d', len(read), self.remoteaddr, self.remoteport) self.Receiver.to_client_buffer += read def writable(self): return len(self.Receiver.from_client_buffer) > 0 def handle_write(self): sent = self.send(self.Receiver.from_client_buffer) self.logger.debug('write --> %04i to %s:%d', sent, self.remoteaddr, self.remoteport) self.Receiver.from_client_buffer = self.Receiver.from_client_buffer[sent:] def handle_close(self): self.close() self.Receiver.close() def main(): parser = optparse.OptionParser() parser.add_option( '-l', '--local-ip', dest='local_ip', help='Local IP address to bind to') parser.add_option( '-p', '--local-port', type='int', dest='local_port', help='Local port to bind to') parser.add_option( '-r', '--remote-ip', dest='remote_ip', help='Local IP address to bind to') parser.add_option( '-P', '--remote-port', type='int', dest='remote_port', help='Remote port to bind to') parser.add_option( '-v', '--verbose', action='store_true', dest='verbose', help='verbose') opts, args = parser.parse_args() if len(sys.argv) == 1 or len(args) > 0: parser.print_help() exit() if not (opts.local_ip and opts.local_port and opts.remote_ip and opts.remote_port): parser.print_help() exit() if opts.verbose: log_level = logging.DEBUG else: log_level = logging.CRITICAL logging.basicConfig(level=log_level, format='%(name)-9s: %(message)s') Forwarder(opts.local_ip, opts.local_port, opts.remote_ip, opts.remote_port) try: asyncore.loop(use_poll=True) except KeyboardInterrupt: print 'quit' exit() if __name__ == '__main__': main()