sudo apt-get install idle-python2.7
//上面可以不输入2.7然后使用tab联想,可以看到还有3.4的版本,这里使用了2.7的版本
2.1 创建日志即日志目录,判断是否有logs这个目录,无则进行创建。然后对这个logging的基本信息进行配置。
logsDir = "logs"
if not os.path.isdir(logsDir);
os.mkdir(logsDir)
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
datefmt='%a,%d %b %Y %H:%M:%S ',
filename='logs/logs.log',
filemode='a')
2.2 设置代理的ip和限制最大代理的数目:
to_addr=('10.13.20.3',3128)
maxConnections = 32
2.3 将所有的代理操作封装成类
2.3.1 首先写这个初始化函数,传入addr,这个是在调用的时候创建。
class Proxy:
def __init__(self,addr):
self.proxy = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
self.proxy.bind(addr)
self.proxy.listen(maxConnections)
self.inputs = {self.proxy:None}
self.route = {}
2.3.1.1 self指的是类实例对象本身,基础知识见self解释
这个类有成员变量 proxy/inputs/route。
2.3.1.2 其中proxy是socket对象,这个socket是流对象,基础知识见python中的socket
将这个proxy对象绑定到指定的地址,并设置最大的监听数目。
2.3.1.3 inputs成员是以proxy为key的一个集合,用来记录从A过来的socket(A–>B—>C—->Internet)
2.3.1.4 route和inputs相反,记录返程socket(A<–B<—C<—-Internet)
2.3.2 在上面的Proxy类中定义这个主要的方法类serve_forever(self)
def serve_forever(self):
logging.info('proxy listen....')
while 1:
readable,_,_=select.select(list(self.inputs.keys()),[],[])
for self.sock in readable:
if self.sock == self.proxy:
self.on_join()
else:
try:
data = self.sock.recv(8192)
except Exception, e:
logging.error(str(e))
self.on_quit()
continue
if not data:
self.on_quit()
else:
try:
self.route[self.sock].send(data)
except Exception,e:
logging.error(str(e))
self.on_quit()
continue
2.3.2.1 这里使用了select模块,基础知识见select解释。
这个select这里是为了承担起服务器和多个客户端通信的作用。select的原型为(rlist,wlist,xlist[,timeout]),rlist是等待读取的对象,wlist是等待写入的对象,xlist是等待异常的对象,最后一个是可选对象,指定等待的时间,单位是s,将要返回对象三元组,所以这里只接收等待读取的对象。
2.3.2.2 如果这个key是proxy对象,执行这个Proxy类的on_join()方法,这个方法具体实现见2.3.3,主要记录从C到A的返程socket(A<–B<—C<—-Internet)
2.3.2.3 如果不是sock.proxy成员,这里主要是看addr是否一致。不一致需要接收数据。接收完成数据需要进行判断if not data,即是否为空,如果不为空,则对这个self.sock进行发送数据。这里使用了self.route[self.sock]来确定要送达目的的socket,例如从A到B收到了报文,这个时候self.route[self.sock]确定了要发往C的socket。如果收到从C回应的报文,则反向发的报文为 self.route[forward] = client。
2.3.2.4 所有有异常的情况下需要执行on_quit()操作,具体见2.3.4。
2.3.3 on_join(self)方法。
def on_join(self):
client,addr = self.proxy.accept()
logging.info("proxy client "+str(addr)+' connect')
forward = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
try:
forward.connect(to_addr)
except Exception, e:
logging.error(str(e))
client.close()
return
self.inputs[client] = None
self.inputs[forward] = None
self.route[client] = forward
self.route[forward] = client
2.3.3.1 这里proxy类是socket对象,调用它的accept方法,具体使用见上面python中socket的解释。accept方法返回一个含有两个元素的 元组(connection,address)。第一个元素connection是新的socket对象,服务器必须通过它与客户通信;第二个元素 address是客户的Internet地址。
2.3.3.2 定义这个forward变量,是一个新的socket对象。并使用connect链接到C设备(A–>B–>C–>internet)。
2.3.3.3 然后在这个route中记录这个返程的报文应该调用的链接。
2.3.4 on_quit()方法,主要是对各个socket进行关闭。
def on_quit(self):
ls = [self.sock]
if self.sock in self.route:
ls.append(self.route[self.sock])
for s in ls:
if s in self.inputs:
del self.inputs[s]
if s in self.route:
del self.route[s]
s.close()
if __name__ == "__main__":
try:
Proxy(('',8192)).serve_forever()
except KeyboardInterrupt, e:
logging.error("KeyboardInterrupt"+str(e))