版权声明:我的码云地址:https://gitee.com/ZzYangHao https://blog.csdn.net/qq_21049875/article/details/82662594
在看完书后,有种想写webserver的感觉,虽然知道写webserver不是那么简单的一回事,设计很多协议以及接口,但是还是想动手体验一下,所以就用python写了一个,为什么用python的话,原因是python语法简短,写起来可能感觉轻松一些。
代码上传到我的码云(中国的github)里了。
看情况更新把T_T
目前仅仅实现:
处理GET请求静态文件,将静态文件放入static文件夹即可通过get请求访问到,当然还是得分文件权限的。
2018.9.12:更新了GET请求动态事件,或者称为视图函数,本来想写一个类似于render_template(‘xxxxx.html’,xxx=xxx)这样的,但是这样就需要引用jinjia模板,或者自己重写一个类似作用的方法,然后映射进去,所以暂时就先实现一个简单的,如下面这样:(hello视图函数负责将url中传入的参数进行求和并返回)
相应的视图函数代码:
@app.route('/hello')
def sum_args(arg):
sum=0
for i in arg:
sum+=int(i)
return sum
对应的结果:
待添加的功能:
处理GET请求动态文件(我已经写了一个简单的路由,因为之前使用过一丁点flask,所以就模仿其外观实现了一个,其内部实现还是挺复杂的),已经快完成了。
处理POST请求
**待完善======================**
PS:代码依旧写得很烂orz
为了方便调试,设置是单线程运行。
代码如下:
import os,stat,sys
import socket,threading
import functools
maxline=2048
curdir=os.getcwd()
class netIO:
datasize=0
def __init__(self,fd):
self.fd=fd
def readline(self,bufsize):
data=b''
tmp=self.fd.recv(1)
while tmp !=b'\n':
data+=tmp
tmp=self.fd.recv(1)
return data.decode('utf-8')
class webServer:
listenNum=10
port=8080
def __init__(self):
self.serfd=socket.socket()
self.view_func={}
def setListenNum(self,num):
self.listenNum=num
def readrequestheader(self,io):
hdr=io.readline(maxline)
while hdr!='\r':
hdr=io.readline(maxline)
print(hdr)
def add_url_rule(self,rule,f):
self.view_func[rule]=f
def findroute(self,rule):
for key in self.view_func.keys():
if rule==key:
return True
return False
def route(self, rule, **options):
def decorator(f):
self.add_url_rule(rule, f)
return f
return decorator
def parseUrl(self,url):
pathindex=url.find('//')
if pathindex>0:
url=url[pathindex:]
args=[]
path=''
isstatic=True
pathindex=url.find('/')
if pathindex>=0:
argsindex=url.find('?')
if argsindex>0:
path+=url[pathindex:argsindex]
tmpurl=url[argsindex+1:]
args=tmpurl.split('&')
isstatic=False
else:
path+=url[pathindex:]
args.append(url[argsindex+1:])
else:
path='/'
return (path,tuple(args),isstatic)
def getfiletype(self,path):
staticfile=['.html','.txt','.jpg','.png','.gif']
i=0
for o in staticfile:
i+=1
if path.find(o) >0:
if i==1:
return 'text/'+o.replace('.','')
else:
return 'image/'+o.replace('.','')
def server_static(self,fd,path,length):
filetype=self.getfiletype(path)
responseline='HTTP/1.0 200 OK\r\n'
severName='Server: Test Web\r\n'
connection='Connection: close\r\n'
content='Content-length: '+str(length)+'\r\n'
contenttype='Content-type: '+filetype+'\r\n'
ret=(responseline+severName+connection+content+contenttype+'\r\n').encode('utf-8')
fd.send(ret)
f=open(curdir+'/static'+path,'r')
buf=f.read()
f.close()
fd.send(buf.encode('utf-8'))
def server_dynamic(self,fd,path,args):
responseline='HTTP/1.0 200 OK\r\n'
severName='Server: Test Web\r\n'
ret=responseline+severName+'\r\n'
try:
func=None
for key in self.view_func.keys():
if path==key:
func=self.view_func[key]
break
if func !=None:
fd.send(ret.encode('utf-8'))
data=func(args)
fd.send(str(data).encode('utf-8'))
else:
self.clienterror(fd,path,'404','Not Found')
except TypeError:
self.clienterror(fd,path,'403','Forbidden')
finally:
return
def clienterror(self,fd,path,errmsgno,msg):
s='<html><title>Error</title>'
body='<body bgcolo=""ffffff"">\r\n'
bodymsg=errmsgno+':'+msg+'\r\n'+'</body></html>\r\n'
body+=bodymsg
body=s+body
ret='HTTP/1.0 '+errmsgno+' '+msg+'\r\n'
contenttype='Content-type: text/html\r\n'
contentlen='Content-length: '+str(len(body))+'\r\n'
ret+=contenttype+contentlen+'\r\n'
fd.send(ret.encode('utf-8'))
fd.send(body.encode('utf-8'))
def doit(self,fd):
io=netIO(fd)
reqline=io.readline(maxline)
method_url_version=[]
for s in reqline.replace('\r\n',' ').split(' '):
method_url_version.append(s)
print(method_url_version)
self.readrequestheader(io)
if(method_url_version[0].upper()=='GET'):
path,args,isstatic=self.parseUrl(method_url_version[1])
if isstatic==True:
try:
static_file=os.stat(curdir+'/static'+path)
except FileNotFoundError:
self.clienterror(fd,path,'404','Not Found')
return
if stat.S_ISREG(static_file.st_mode) !=True or (stat.S_IRUSR & static_file.st_mode) ==False:
self.clienterror(fd,path,'403','Forbidden')
return
self.server_static(fd,path,static_file.st_size)
else:
if self.findroute(path) ==False:
self.clienterror(fd,path,'404','Not Found')
return
self.server_dynamic(fd,path,args)
fd.close()
def run(self,ip='',port=8080):
serfd=self.serfd
serfd.bind((ip,port))
serfd.listen(self.listenNum)
while(1):
confd,addr=serfd.accept()
print('accept connection from : ',addr)
#m_thread=threading.Thread(target=webServer.doit,args=(self,confd,))
#m_thread.setDaemon(True)
#m_thread.start()
self.doit(confd)
app=webServer()
@app.route('/hello')
def sum_args(arg):
sum=0
for i in arg:
sum+=int(i)
return sum
app.run()