这篇文章想写得是一个简单的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 pageif __name__ == '__main__': serverAddress = ('', 8080) server = BaseHTTPServer.HTTPServer(serverAddress, RequestHandler) server.serve_forever()
运行结果:
image.png
对于html 请求的响应,其实就是拿去这个url请求后面的路径,然后在服务器的目录下面去找这个文件,如果有,就返回给浏览器。如果没有,就返回404状态码。
下面是demo3:
#coding:utf-8import sys,os,BaseHTTPServerclass 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
作者:sexycoder
链接:https://www.jianshu.com/p/2fc93de02b94