Python实现简单的Web服务器 Part1

作者: DayDayUpppppp | 来源:发表于2017-03-04 16:38 被阅读1267次
    这篇文章想写得是一个简单的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

    相关文章

      网友评论

      本文标题:Python实现简单的Web服务器 Part1

      本文链接:https://www.haomeiwen.com/subject/yvcjgttx.html