这篇文章想写得是一个简单的web服务器。
首先可能需要了解一点网络编程,web服务器,简单的说,运行在一台机器上的一个进程(通常不在本地),浏览器也是运行在机器上的一个进程(本地的)。也就是说,他的本质其实就是一个跨机器的进程通信。
然后,实现了跨机器的通信之后,服务器和浏览器通信的数据格式,其实就是http协议。也就是说,浏览器和服务器必须按照http协议规定的格式发送数据,要不然的话,对方就听不懂了。
关于网络编程的知识,你可以参考:
http://www.jianshu.com/p/8f1941c4a549
关于http协议的知识,你可以参考:
超简洁的实例 ——关于HTTP协议分析 http://www.jianshu.com/p/f5a5db039737
关于实现一个web服务器
初步的功能是这样,运行服务器之后,在局域网内的设备可以访问这个服务器。比如,我在服务器下面放了一个class.html 文件,这是我的课表。当我用手机访问这个网页的时候,在手机的浏览器中显示这个页面。如下图:(随便写得一个html文件,虽然丑,但是模拟一下这个功能就好)
局域网内手机访问.png pc访问.png
这篇文章只写了一个静态的web服务器,下一篇文章写了 模拟实现cgi,支持脚本语言:
Python实现简单的Web服务器 Part2
http://www.jianshu.com/p/d28395655bc0
python 下有一个库BaseHTTPServer,这个库封装了一个常用的处理http协议的请求和响应的函数,如果用这个库,基本上就不需要考虑网络层的实现了,只需要了解http协议就好。
但是也可以从网络层写起,利用socket编程。这样你需要考虑的一个很重要的问题就是:服务器处理并发,是多线程还是多进程,还是异步模型,或者是多进程+多线程。现在感觉网络编程真的是博大精深。
这样一个最简单的服务器就写好了,但是他不能对浏览器请求的页面做出响应,对于所有的请求,服务器回复 “to-do”
import BaseHTTPServer
#RequestHandler 繼承 BaseHTTPRequestHandler
class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
'''处理请求并返回页面'''
# 页面模板
Page = "to do "
#do_GET的函數的名字 是不能改的
def do_GET(self):
self.send_response(200)
self.send_header("Content-Type", "text/html")
self.send_header("Content-Length", str(len(self.Page)))
self.end_headers()
self.wfile.write(self.Page)
if __name__ == '__main__':
serverAddress = ('', 8080)
server = BaseHTTPServer.HTTPServer(serverAddress, RequestHandler)
server.serve_forever()
demo2 依然不可以响应不同的html文件请求,但是可以利用基类的数据成员来输出http请求的时间,端口,请求的html文件。
#-*- coding:utf-8 -*-
import BaseHTTPServer
#RequestHandler 繼承 BaseHTTPRequestHandler ,所以他自身就有一個path的數據成員
class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
#Page="to doing wakakak "
Page='''
<html>
<body>
<table>
<tr> <td>Header</td> <td>Value</td> </tr>
<tr> <td>Date and time</td> <td>{date_time}</td> </tr>
<tr> <td>Client host</td> <td>{client_host}</td> </tr>
<tr> <td>Client port</td> <td>{client_port}</td> </tr>
<tr> <td>Command</td> <td>{command}</td> </tr>
<tr> <td>Path</td> <td>{path}</td> </tr>
</table>
</body>
</html>
'''
#
def do_GET(self):
#self.send_response(200)
#self.send_header('Content-Type','text/html')
#self.send_header('Content-Length',str(len(self.Page)))
#self.end_headers()
#self.wfile.write(self.Page)
page=self.create_page()
self.send_content(page)
def send_content(self,page):
self.send_response(200)
self.send_header('Content-Type','text/html')
self.send_header('Content-Length','text.html')
self.end_headers()
self.wfile.write(page)
#self.date_time_string 和 client_address[0/1]等等都是父類的書據成員
def create_page(self):
values={
'date_time':self.date_time_string(),
'client_host':self.client_address[0],
'client_port':self.client_address[1],
'command':self.command,
'path':self.path
}
page=self.Page.format(**values)
return page
if __name__ == '__main__':
serverAddress = ('', 8080)
server = BaseHTTPServer.HTTPServer(serverAddress, RequestHandler)
server.serve_forever()
运行结果:
image.png
对于html 请求的响应,其实就是拿去这个url请求后面的路径,然后在服务器的目录下面去找这个文件,如果有,就返回给浏览器。如果没有,就返回404状态码。
下面是demo3:
#coding:utf-8
import sys,os,BaseHTTPServer
class ServerException(Exception):
pass
#RequestHandler 繼承 BaseHTTPRequestHandler ,所以他自身就有一個path的數據成員
class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
Error_Page="""\
<html>
<body>
<h1>Error accessing {path}</h1>
<p>{msg}</p>
</body>
</html>
"""
def do_GET(self):
try:
print 'get'
full_path=os.getcwd()+self.path
print full_path
print os.getcwd()
if not os.path.exists(full_path):
raise ServerException("'{ 0 }' not found ",format(self.path))
elif os.path.isfile(full_path):
self.handle_file(full_path)
else:
raise ServerException("unkown object '{ 0 }'",format(self.path))
except Exception as msg:
self.handle_error(msg)
def handle_file(self,full_path):
try:
with open(full_path,'rb') as reader:
content=reader.read()
self.send_content(content)
except IOError as msg:
msg="'{0}' cannot be read :{1} ".format(self.path,msg)
self.handle_error(msg)
def handle_error(self,msg):
content=self.Error_Page.format(path=self.path,msg=msg)
self.send_content(content,404)
def send_content(self,page,status=200):
#print 'send_content function '
self.send_response(status)
self.send_header('Content-Type','text/html')
self.send_header('Content-Length','text.html')
self.end_headers()
self.wfile.write(page)
if __name__ == '__main__':
serverAddress = ('', 8081)
server = BaseHTTPServer.HTTPServer(serverAddress, RequestHandler)
server.serve_forever()
运行结果就是第一张图那法样,实现了一个简单的静态服务器。
git链接:https://github.com/zhaozhengcoder/Python
下一步,试着去模拟实现一些cgi
//to-do 吃饭去了 好饿
后续可以参考:
Python实现简单的Web服务器 Part2 http://www.jianshu.com/p/d28395655bc0
网友评论