400行python 实现http/https 代理服务器
发布时间:2020-12-17 17:15:17 所属栏目:Python 来源:网络整理
导读:今天PHP站长网 52php.cn把收集自互联网的代码分享给大家,仅供参考。 #!/usr/bin/python#-*- coding:utf-8 -*-import socket,loggingimport select,errnoimport osimport sysimport tracebackimport gzipfrom StringIO im
以下代码由PHP站长网 52php.cn收集自互联网 现在PHP站长网小编把它分享给大家,仅供参考 #!/usr/bin/python #-*- coding:utf-8 -*- import socket,logging import select,errno import os import sys import traceback import gzip from StringIO import StringIO import Queue import threading import time import thread import cgi from cgi import parse_qs import json import imp from os.path import join,getsize import re import ssl ##################user config ################## logger = logging.getLogger("network-server") ############################################# def getTraceStackMsg(): tb = sys.exc_info()[2] msg = '' for i in traceback.format_tb(tb): msg += i return msg def InitLog(): logger.setLevel(logging.DEBUG) fh = logging.FileHandler("network-server.log") fh.setLevel(logging.DEBUG) ch = logging.StreamHandler() ch.setLevel(logging.ERROR) formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") ch.setFormatter(formatter) fh.setFormatter(formatter) logger.addHandler(fh) logger.addHandler(ch) def clearfdpro(epoll_fd,params,fd): try: fd_check = int(fd) except Exception,e: print "fd error" sys.exit(1) try: #print "pid:%s,close fd:%s" % (os.getpid(),fd) epoll_fd.unregister(fd) except Exception,e: #print str(e)+getTraceStackMsg() pass try: param = params[fd] try: addr = param["addr"] if "next" in param: print "close sock,%s:%s" % (addr[0],addr[1]) except Exception,e: pass param["connections"].shutdown(socket.SHUT_RDWR) param["connections"].close() f = param.get("f",None) if f != None: f.close() rc = param.get("rc",None) if rc != None: rc.close() if "read_cache_name" in param: os.remove(param["read_cache_name"]) except Exception,e: #print str(e)+getTraceStackMsg() pass try: del params[fd] #logger.error(getTraceStackMsg()) #logger.error("clear fd:%s" % fd) except Exception,e: #print str(e)+getTraceStackMsg() pass def clearfd(epoll_fd,fd): try: param = params[fd] if "nextfd" in param: nextfd = param["nextfd"] next_param = params[nextfd] del param["nextfd"] del next_param["nextfd"] if not "next" in param: #masterfd clearfdpro(epoll_fd,nextfd) else: # nextfd if not "writedata" in next_param or len(next_param["writedata"]) == 0: clearfdpro(epoll_fd,nextfd) else: next_param["sendandclose"] = "true" clearfdpro(epoll_fd,fd) except Exception,e: #print str(e)+getTraceStackMsg() pass def FindHostPort(datas): host_s = -1 host_e = -1 host_str = None host = "" port = "" if not datas.startswith("CONNECT"): host_s = datas.find("Host:") if host_s < 0: host_s = datas.find("host:") if host_s > 0: host_e = datas.find("rn",host_s) if host_s > 0 and host_e > 0: host_str = datas[host_s+5:host_e].strip() add_list = host_str.split(":") if len(add_list) == 2: host = add_list[0] port = add_list[1] else: host = add_list[0] port = 80 first_seg = datas.find("rn") first_line = datas[0:first_seg] first_line = first_line.replace(" http://%s" % host_str," ") datas = first_line + datas[first_seg:] else: first_seg = datas.find("rn") head_e = datas.find("rnrn") if first_seg > 0 and head_e > 0: first_line = datas[0:first_seg] com,host_str,http_version = re.split('s+',first_line) add_list = host_str.split(":") if len(add_list) == 2: host = add_list[0] port = add_list[1] else: host = add_list[0] port = 443 host_s = 1 host_e = 1 return host_str,host_s,host_e,host,port,datas def connect_pro(params,param,epoll_fd,datas,fd,cur_time,port): try: nextfd = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0) nextfd.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) nextfd.settimeout(5) try: nextfd.connect((host,int(port))) except Exception,e: print "########%s,%s connect fail" % (host,port) nextfd.setblocking(0) next_fileno = nextfd.fileno() print "pid:%s,connect %s:%s fd:%s" % (os.getpid(),next_fileno) if next_fileno in params: print "fileno exist" sys.exit(1) if not datas.startswith("CONNECT"): next_param = {"addr":[host,port],"writelen":0,"connections":nextfd,"time":cur_time,"nextfd":fd} param["nextfd"] = next_fileno next_param["writedata"] = datas next_param["writelen"] = 0 next_param["next"] = "true" param["read_len"] = 0 param["readdata"] = "" params[next_fileno] = next_param epoll_fd.register(next_fileno,select.EPOLLIN | select.EPOLLOUT | select.EPOLLERR | select.EPOLLHUP) epoll_fd.modify(fd,select.EPOLLIN | select.EPOLLERR | select.EPOLLHUP) else: next_param = {"addr":[host,"nextfd":fd} param["nextfd"] = next_fileno next_param["next"] = "true" params[next_fileno] = next_param epoll_fd.register(next_fileno,select.EPOLLIN | select.EPOLLERR | select.EPOLLHUP) param["read_len"] = 0 param["readdata"] = "" param["writedata"] = "HTTP/1.1 200 Connection EstablishedrnConnection: closernrn" param["writelen"] = 0 param["reuse"] = "true" epoll_fd.modify(fd,select.EPOLLIN | select.EPOLLOUT | select.EPOLLERR | select.EPOLLHUP) except socket.error,msg: clearfd(epoll_fd,fd) def process_datas(process_status,read_len,cur_time): if process_status == "close": clearfd(epoll_fd,fd) else: need_connect = False host_str = None host_s = -1 host_e = -1 if "reuse" in param and "next" not in param: if not datas.startswith("CONNECT") and not datas.startswith("GET") and not datas.startswith("POST") and not datas.startswith("PUT"): del param["reuse"] else: host_str,datas = FindHostPort(datas) host_s = int(host_s) host_e = int(host_e) next_fileno = param["nextfd"] next_param = params[next_fileno] addr = next_param["addr"] if host_s > 0 and host_e > 0: if host != addr[0] or str(port) != str(addr[1]): print "%s,%s neq %s,%s" % (host,addr[0],addr[1]) need_connect = True del param["nextfd"] del next_param["nextfd"] clearfd(epoll_fd,next_fileno) del param["reuse"] else: param["read_len"] = read_len param["readdata"] = datas return None if need_connect or not "nextfd" in param: if host_str == None or not host_s > 0 or not host_e > 0: host_str,datas = FindHostPort(datas) host_s = int(host_s) host_e = int(host_e) if host_s > 0 and host_e > 0: if not datas.startswith("CONNECT"): epoll_fd.modify(fd,select.EPOLLERR | select.EPOLLHUP) # 简单处理,http连接时把读去掉,避免内存攻击 thread.start_new_thread(connect_pro,(params,port)) else: param["read_len"] = read_len param["readdata"] = datas else: next_fileno = param["nextfd"] next_param = params[next_fileno] if "next" in param: next_param["reuse"] = "true" write_data = next_param.get("writedata","") write_data += datas next_param["writedata"] = write_data param["read_len"] = 0 param["readdata"] = "" epoll_fd.modify(next_fileno,select.EPOLLIN | select.EPOLLOUT | select.EPOLLERR | select.EPOLLHUP) if process_status == "close_after_process": print "close after process" clearfd(epoll_fd,fd) def run_main(listen_fd): try: epoll_fd = select.epoll() epoll_fd.register(listen_fd.fileno(),select.EPOLLIN | select.EPOLLERR | select.EPOLLHUP) print "listen_fd:%s" % listen_fd.fileno() except select.error,msg: logger.error(msg) params = {} last_min_time = -1 while True: epoll_list = epoll_fd.poll() cur_time = time.time() for fd,events in epoll_list: if fd == listen_fd.fileno(): while True: try: conn,addr = listen_fd.accept() conn.setblocking(0) epoll_fd.register(conn.fileno(),select.EPOLLIN | select.EPOLLERR | select.EPOLLHUP) conn.setsockopt(socket.SOL_SOCKET,1) #conn.setsockopt(socket.IPPROTO_TCP,socket.TCP_NODELAY,True) params[conn.fileno()] = {"addr":addr,"connections":conn,"time":cur_time} except socket.error,msg: break elif select.EPOLLIN & events: param = params.get(fd,None) if param == None: continue param["time"] = cur_time datas = param.get("readdata","") cur_sock = params[fd]["connections"] read_len = param.get("read_len",0) process_status = "close" while True: try: data = cur_sock.recv(102400) if not data: if datas == "": break else: raise Exception("close after process") else: datas += data read_len += len(data) except socket.error,msg: if msg.errno == errno.EAGAIN: process_status = "process" break else: break except Exception,e: process_status = "close_after_process" break process_datas(process_status,cur_time) elif select.EPOLLHUP & events or select.EPOLLERR & events: clearfd(epoll_fd,fd) logger.error("sock: %s error" % fd) elif select.EPOLLOUT & events: param = params.get(fd,None) if param == None: continue param["time"] = cur_time sendLen = param.get("writelen",0) writedata = param.get("writedata","") total_write_len = len(writedata) cur_sock = param["connections"] f = param.get("f",None) totalsenlen = param.get("totalsenlen",None) if writedata == "": clearfd(epoll_fd,fd) continue while True: try: sendLen += cur_sock.send(writedata[sendLen:]) if sendLen == total_write_len: if f != None and totalsenlen != None: readmorelen = 102400 if readmorelen > totalsenlen: readmorelen = totalsenlen morefiledata = "" if readmorelen > 0: morefiledata = f.read(readmorelen) if morefiledata != "": writedata = morefiledata sendLen = 0 total_write_len = len(writedata) totalsenlen -= total_write_len param["writedata"] = writedata param["totalsenlen"] = totalsenlen continue else: f.close() del param["f"] del param["totalsenlen"] if not "sendandclose" in param: param["writedata"] = "" param["writelen"] = 0 epoll_fd.modify(fd,select.EPOLLIN | select.EPOLLERR | select.EPOLLHUP) else: clearfd(epoll_fd,fd) break except socket.error,msg: if msg.errno == errno.EAGAIN: param["writelen"] = sendLen break clearfd(epoll_fd,fd) break else: continue #check time out if cur_time - last_min_time > 20: last_min_time = cur_time objs = params.items() for (key_fd,value) in objs: fd_time = value.get("time",0) del_time = cur_time - fd_time if del_time > 20: clearfd(epoll_fd,key_fd) elif fd_time < last_min_time: last_min_time = fd_time if __name__ == "__main__": reload(sys) sys.setdefaultencoding('utf8') InitLog() port = int(sys.argv[1]) try: listen_fd = socket.socket(socket.AF_INET,0) except socket.error,msg: logger.error("create socket failed") try: listen_fd.setsockopt(socket.SOL_SOCKET,1) except socket.error,msg: logger.error("setsocketopt SO_REUSEADDR failed") try: listen_fd.bind(('',port)) except socket.error,msg: logger.error("bind failed") try: listen_fd.listen(10240) listen_fd.setblocking(0) except socket.error,msg: logger.error(msg) child_num = 19 c = 0 while c < child_num: c = c + 1 newpid = os.fork() if newpid == 0: run_main(listen_fd) run_main(listen_fd) 以上内容由PHP站长网【52php.cn】收集整理供大家参考研究 如果以上内容对您有帮助,欢迎收藏、点赞、推荐、分享。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |