最近打算好好深入研究下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
主要意思就是說,內建函式或方法無法擁有下標,你懂的