python实战--Http代理服务器

kkkkk 2018年12月17日 22:48 Python基础

最近打算好好深入研究下python的socket编程, 于是打算学习下,仿写了一下,发现写好还真不容易,中途出现很多问题,果真是看的容易,做起来难啊

import socket 
import thread 
import urlparse 
import select 
  
BUFLEN=8192
  
  
class Proxy(object): 
    def __init__(self,conn,addr): 
        self.source=conn 
        self.request="" 
        self.headers={} 
        self.destnation=socket.socket(socket.AF_INET,socket.SOCK_STREAM) 
        self.run() 
  
    def get_headers(self): 
        header='' 
        while True: 
            header+=self.source.recv(BUFLEN) 
            index=header.find('\n') 
            if index >0: 
                break
        #firstLine,self.request=header.split('\r\n',1)  
        firstLine=header[:index] 
        self.request=header[index+1:] 
        self.headers['method'],self.headers['path'],self.headers['protocol']=firstLine.split() 
  
    def conn_destnation(self): 
        url=urlparse.urlparse(self.headers['path']) 
        hostname=url[1] 
        port="80"
        if hostname.find(':') >0: 
            addr,port=hostname.split(':') 
        else: 
            addr=hostname 
        port=int(port) 
        ip=socket.gethostbyname(addr) 
        print ip,port 
        self.destnation.connect((ip,port)) 
        data="%s %s %s\r\n" %(self.headers['method'],self.headers['path'],self.headers['protocol']) 
        self.destnation.send(data+self.request) 
        print data+self.request 
  
  
    def renderto(self): 
        readsocket=[self.destnation] 
        while True: 
            data='' 
            (rlist,wlist,elist)=select.select(readsocket,[],[],3) 
            if rlist: 
                data=rlist[0].recv(BUFLEN) 
                if len(data)>0: 
                    self.source.send(data) 
                else: 
                    break
    def run(self): 
        self.get_headers() 
        self.conn_destnation() 
        self.renderto() 
  
  
  
class Server(object): 
  
    def __init__(self,host,port,handler=Proxy): 
        self.host=host 
        self.port=port 
        self.server=socket.socket(socket.AF_INET,socket.SOCK_STREAM) 
        self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
        self.server.bind((host,port)) 
        self.server.listen(5) 
        self.handler=handler 
  
    def start(self): 
        while True: 
            try: 
                conn,addr=self.server.accept() 
                thread.start_new_thread(self.handler,(conn,addr)) 
            except: 
                pass
  
  
if __name__=='__main__': 
    s=Server('127.0.0.1',8080) 
    s.start() 
import socket
import thread
import urlparse
import select
BUFLEN=8192
class Proxy(object):
    def __init__(self,conn,addr):
        self.source=conn
        self.request=""
        self.headers={}
        self.destnation=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        self.run()
    def get_headers(self):
        header=''
        while True:
            header+=self.source.recv(BUFLEN)
            index=header.find('\n')
            if index >0:
                break
        #firstLine,self.request=header.split('\r\n',1)
        firstLine=header[:index]
        self.request=header[index+1:]
        self.headers['method'],self.headers['path'],self.headers['protocol']=firstLine.split()
    def conn_destnation(self):
        url=urlparse.urlparse(self.headers['path'])
        hostname=url[1]
        port="80"
        if hostname.find(':') >0:
            addr,port=hostname.split(':')
        else:
            addr=hostname
        port=int(port)
        ip=socket.gethostbyname(addr)
        print ip,port
        self.destnation.connect((ip,port))
        data="%s %s %s\r\n" %(self.headers['method'],self.headers['path'],self.headers['protocol'])
        self.destnation.send(data+self.request)
        print data+self.request
    def renderto(self):
        readsocket=[self.destnation]
        while True:
            data=''
            (rlist,wlist,elist)=select.select(readsocket,[],[],3)
            if rlist:
                data=rlist[0].recv(BUFLEN)
                if len(data)>0:
                    self.source.send(data)
                else:
                    break
    def run(self):
        self.get_headers()
        self.conn_destnation()
        self.renderto()
  
class Server(object):
    def __init__(self,host,port,handler=Proxy):
        self.host=host
        self.port=port
        self.server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.server.bind((host,port))
        self.server.listen(5)
        self.handler=handler
    def start(self):
        while True:
            try:
                conn,addr=self.server.accept()
                thread.start_new_thread(self.handler,(conn,addr))
            except:
                pass
if __name__=='__main__':
    s=Server('127.0.0.1',8080)
    s.start()

其实Http代理服务器本身不难,但写出来还是挺费事的,这里就不细说源代码了,很简单。主要说说,我遇到的问题。

一: 我本来只知道,thread.start_new_thread的第一个参数是函数对象,但当我看到上面的博文时,心里一愣,这样也可以,于是我迅速的测试了一下:

import thread 
  
class Hello: 
    def __init__(self,content): 
        print content 
  
def cs(): 
        thread.start_new_thread(Hello, ("Hello World",)) 
  
if __name__=='__main__': 
    cs() 
import thread
class Hello:
    def __init__(self,content):
        print content
def cs():
        thread.start_new_thread(Hello, ("Hello World",))
if __name__=='__main__':
    cs()

Unhandled exception in thread started by  
Error in sys.excepthook:

Original exception was:

Unhandled exception in thread started by
Error in sys.excepthook:

Original exception was:

一看,我说嘛,第一个参数怎么可以是对象,我呵呵一笑,稍微鄙视了一下作者。于是,我洗洗睡了,第二天,我还是不死心,于是把代码下下来,本地实验了一下,可以的,立马意识到是我2了,于是立马百度。

原来thread模块中,主线程如果比子线程先结束,就会抛出这个异常,所以我们必须让子线程先结束,最简单的方法就是让主线程sleep足够长的时间,至于多长时间,貌似不知道,那到底怎么解决呢?

比较好的解决办法就是,主线程给每个子线程都加一把锁,子线程在结束前将锁释放掉,主线程一直循环检查锁的状态。代码如下:

import thread 
  
class Hello: 
    def __init__(self,content,lock): 
        print content 
        """
        do something
        ....
        At the end,release the lock
        """
        lock.release() 
  
def cs(): 
        lock=thread.allocate_lock() 
        lock.acquire() 
        thread.start_new_thread(Hello, ("Hello World",lock)) 
        while True: 
            if not lock.locked(): 
                break
        print "lock release"
  
if __name__=='__main__': 
    cs() 
import thread
class Hello:
    def __init__(self,content,lock):
        print content
        """
        do something
        ....
        At the end,release the lock
        """
        lock.release()
def cs():
        lock=thread.allocate_lock()
        lock.acquire()
        thread.start_new_thread(Hello, ("Hello World",lock))
        while True:
            if not lock.locked():
                break
        print "lock release"
if __name__=='__main__':
    cs()

二.第二个错误就是比较2的了

self.source.send[data]

peError: 'builtin_function_or_method' object is unsubscriptable

 self.source.send[data]

TypeError: 'builtin_function_or_method' object is unsubscriptable

主要意思就是说,内置函数或方法无法拥有下标,你懂的



文章评论(0)
  • avatar kkkkkk 2018年12月21日 11:31
    真干活啊
    kkkkk
    2018年12月21日 11:16
    行文思路简单肤浅,文章结构平面呆板。
    回复
  • avatar kkkkkk 2018年12月21日 11:31
    哇塞!
    kkkkklxinde
    2018年12月21日 11:17
    本文立意正确,紧扣材料说理,观点鲜明而集中,能简练概述作文材料,表达流畅而简洁,体现了较强的语言驱遣能力。比喻、说理等多种方法的运用,使论证具有说服力。诸多引用尤为精彩,体现了作者一定的学养。
    回复
  • avatar kkkkklxinde 2018年12月21日 11:17
    本文立意正确,紧扣材料说理,观点鲜明而集中,能简练概述作文材料,表达流畅而简洁,体现了较强的语言驱遣能力。比喻、说理等多种方法的运用,使论证具有说服力。诸多引用尤为精彩,体现了作者一定的学养。
    回复
  • avatar kkkkk 2018年12月21日 11:16
    行文思路简单肤浅,文章结构平面呆板。
    回复