python代理服务器

来源:互联网 发布:windows 7 位置不可用 编辑:程序博客网 时间:2024/05/29 12:14

著名的google翻墙工具goagent就是用python写的。这几天我也用python凑合着写了一个代理服务器,最近忙着准备GRE考试,就写了http的,https留着以后再说。编出来之后用chrome浏览器+SwithySharp插件测试可用。

代理的原理其实很简单,说穿了就是个中转站:浏览器发请求给代理,代理从中提取目标主机(Host)信息进行连接并转发请求,从目标主机获取响应并转发给浏览器。技术上来说,需要对http报文结构、socket用法、异常的处理(网络连接经常会出现异常)有一定的了解。值得注意的是,浏览器发给代理的请求会与直接发给目标主机的请求略有不同,需要代理程序对其进行修改。具体来说,发给代理的请求会将整个url作为资源地址,而非代理则会省去地址里面的http://*******(其中*代表主机地址)。如果还不清楚的话可以利用抓包软件进行比较。

python版本是3.4.0,用到了python自带的socket库和_thread库。下面贴代码:

'''Function: ProxyIllustration: Only for 'http', not 'https'Finish Date: the 6th of Auguest, 2014Author: Peizhong JuPython version: 3.4.0'''import socketimport _threaddef getAim(req):    '''    Function: Find the host from the request.    '''    temp = req.decode()    start = temp.find('Host')    length = temp[start:].find('\r')    return temp[start + 6:start + length]def modifyReq(req):    '''    Function: Modify the request.    Illustration: In this version, order of 'CONNECT' will not be handled.    '''    if not req:        return req    temp = req.decode()    cn=temp.find('\n')-10    firstLine = temp[:cn].split()    if firstLine[0] == 'CONNECT':        return ''.encode()    print(firstLine)    tmp = firstLine[1].split('/')    net = tmp[0] + '//' + tmp[2]    temp = temp[:cn].replace(net, '') + temp[cn:]    return temp.encode()def handleReq():    '''    Function: Do the proxy job.    '''    global waiting_list    c = waiting_list.pop(0)    c.settimeout(0.1)    request = b''    try:        while True:            buf = c.recv(1024)            if not buf:                break            request = request + buf    except socket.timeout:        request = modifyReq(request)        if not request:            return        try:            cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM)            cli.settimeout(0.2)                        try:                cli.connect((getAim(request), 80))            except socket.gaierror:                print("Cannot connect to", '"' + getAim(request) + '"!')                return                        try:                cli.sendall(request)            except ConnectionAbortedError:                return            #print("Transmitting data...")            while True:                buf = cli.recv(1024)                if not buf:                    break                try:                    c.sendall(buf)                    #print(" || ", end = '')                except ConnectionAbortedError:                    print("Connection failed.")                    continue        except socket.timeout:            #print("\nTransmitting finished.")            cli.close()            returnif __name__ == '__main__':    srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)    srv.bind(('localhost', 5814)) # define the address and the port of the proxy server    srv.listen(50)    waiting_list = []    while True:        conn, addr = srv.accept()        waiting_list.append(conn)        _thread.start_new_thread(handleReq,())


0 0