• python网络-动态Web服务器案例(30)


    一、浏览器请求HTML页面的过程

      了解了HTTP协议和HTML文档,其实就明白了一个Web应用的本质就是:

    1. 浏览器发送一个HTTP请求;

    2. 服务器收到请求,生成一个HTML文档;

    3. 服务器把HTML文档作为HTTP响应的Body发送给浏览器;

    4. 浏览器收到HTTP响应,从HTTP Body取出HTML文档并显示。

    二、浏览器请求动态页面的过程

    三、WSGI

    1、WSGI介绍

    PythonWeb服务器网关接口(Python Web Server Gateway Interface,缩写为WSGI)是Python应用程序或框架和Web服务器之间的一种接口,

    WSGI接口定义非常简单,它只要求Web开发者实现一个函数,就可以响应HTTP请求。

    # WSGI 规范的函数
    def
    application(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) return '<h1>Hello, Se7eN_HOU!</h1>'

    上面的application()函数就是符合WSGI标准的一个HTTP处理函数,它接收两个参数:

      • environ:一个包含所有HTTP请求信息的dict对象;

      • start_response:一个发送HTTP响应的函数。

    application()函数中,调用:

    start_response('200 OK', [('Content-Type', 'text/html')])

    2、运行WSGI服务

    1、 Python内置了一个WSGI服务器,这个模块叫wsgiref,首先我们先实现一个hello.py文件,实现Web应用程序的WSGI处理函数

    def application(environ, start_response):
        start_response("200 OK",[("Content-Type","text/html")])
        return "<h1>Hello,Se7eN_HOU!</h1>"

    2、然后,再编写一个server.py,负责启动WSGI服务器,加载application()函数: 

     

    #coding:utf-8
    
    # 导入wsgiref模块
    from wsgiref.simple_server import make_server
    from hello import application
    
    
    # 创建一个服务器,IP地址为空,端口号为7788,处理的函数是application
    httpServer = make_server("", 7788, application)
    # 开始监听HTTP请求
    httpServer.serve_forever()

    3、确保以上两个文件在同一个目录下,然后使用命令行输入python server.py来启动WSGI服务器:

    houleideMacPro:WSGI Se7eN_HOU$ python server.py
    127.0.0.1 - - [19/Jun/2019 15:52:37] "GET / HTTP/1.1" 200 24
    127.0.0.1 - - [19/Jun/2019 15:52:37] "GET /favicon.ico HTTP/1.1" 200 24   

      4、 按Ctrl+C终止服务器。如果你觉得这个Web应用太简单了,可以稍微改造一下,从environ里读取PATH_INFO,这样可以显示更加动态的内容:

    def application(environ, start_response):
        start_response("200 OK",[("Content-Type","text/html")])
        return "<h1>Hello,%s</h1>"%(environ["PATH_INFO"][1:] or "Se7eN_HOU")

      5、你可以在地址栏输入用户名作为URL的一部分,将返回Hello, xxx

     

    四、动态web服务器案例

    1、Daynamic.py

    #coding=utf-8
    import socket
    import sys
    from multiprocessing import Process
    import re
    
    class WSGIServer(object):
    
        addressFamily = socket.AF_INET
        socketType = socket.SOCK_STREAM
        requestQueueSize = 5
    
        def __init__(self, serverAddress):
            #创建一个tcp套接字
            self.listenSocket = socket.socket(self.addressFamily,self.socketType)
            #允许重复使用上次的套接字绑定的port
            self.listenSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            #绑定
            self.listenSocket.bind(serverAddress)
            #变为被动,并制定队列的长度
            self.listenSocket.listen(self.requestQueueSize)
    
            self.servrName = "localhost"
            self.serverPort = serverAddress[1]
    
        def serveForever(self):
            '循环运行web服务器,等待客户端的链接并为客户端服务'
            while True:
                #等待新客户端到来
                self.clientSocket, client_address = self.listenSocket.accept()
    
                #方法2,多进程服务器,并发服务器于多个客户端
                newClientProcess = Process(target = self.handleRequest)
                newClientProcess.start()
    
                #因为创建的新进程中,会对这个套接字+1,所以需要在主进程中减去依次,即调用一次close
                self.clientSocket.close()
    
        def setApp(self, application):
            '设置此WSGI服务器调用的应用程序入口函数'
            self.application = application
    
        def handleRequest(self):
            '用一个新的进程,为一个客户端进行服务'
            self.recvData = self.clientSocket.recv(2014)
            requestHeaderLines = self.recvData.splitlines()
            for line in requestHeaderLines:
                print(line)
    
            httpRequestMethodLine = requestHeaderLines[0]
            getFileName = re.match("[^/]+(/[^ ]*)", httpRequestMethodLine).group(1)
            print("file name is ===>%s"%getFileName) #for test
    
            if getFileName[-3:] != ".py":
    
                if getFileName == '/':
                    getFileName = documentRoot + "/index.html"
                else:
                    getFileName = documentRoot + getFileName
    
                print("file name is ===2>%s"%getFileName) #for test
    
                try:
                    f = open(getFileName)
                except IOError:
                    responseHeaderLines = "HTTP/1.1 404 not found
    "
                    responseHeaderLines += "
    "
                    responseBody = "====sorry ,file not found===="
                else:
                    responseHeaderLines = "HTTP/1.1 200 OK
    "
                    responseHeaderLines += "
    "
                    responseBody = f.read()
                    f.close()
                finally:
                    response = responseHeaderLines + responseBody
                    self.clientSocket.send(response)
                    self.clientSocket.close()
            else:
                #处理接收到的请求头
                self.parseRequest()
    
                #根据接收到的请求头构造环境变量字典
                env = self.getEnviron()
    
                #调用应用的相应方法,完成动态数据的获取
                bodyContent = self.application(env, self.startResponse)
    
                #组织数据发送给客户端
                self.finishResponse(bodyContent)
    
        def parseRequest(self):
            '提取出客户端发送的request'
            requestLine = self.recvData.splitlines()[0]
            requestLine = requestLine.rstrip('
    ')
            self.requestMethod, self.path, self.requestVersion = requestLine.split(" ")
    
        def getEnviron(self):
            env = {}
            env['wsgi.version']      = (1, 0)
            env['wsgi.input']        = self.recvData
            env['REQUEST_METHOD']    = self.requestMethod    # GET
            env['PATH_INFO']         = self.path             # /index.html
            return env
    
        def startResponse(self, status, response_headers, exc_info=None):
            serverHeaders = [
                ('Date', 'Tue, 31 Mar 2016 10:11:12 GMT'),
                ('Server', 'WSGIServer 0.2'),
            ]
            self.headers_set = [status, response_headers + serverHeaders]
    
        def finishResponse(self, bodyContent):
            try:
                status, response_headers = self.headers_set
                #response的第一行
                response = 'HTTP/1.1 {status}
    '.format(status=status)
                #response的其他头信息
                for header in response_headers:
                    response += '{0}: {1}
    '.format(*header)
                #添加一个换行,用来和body进行分开
                response += '
    '
                #添加发送的数据
                for data in bodyContent:
                    response += data
    
                self.clientSocket.send(response)
            finally:
                self.clientSocket.close()
    
    #设定服务器的端口
    serverAddr = (HOST, PORT) = '', 8888
    #设置服务器静态资源的路径
    documentRoot = './html'
    #设置服务器动态资源的路径
    pythonRoot = './wsgiPy'
    
    def makeServer(serverAddr, application):
        server = WSGIServer(serverAddr)
        server.setApp(application)
        return server
    
    def main():
    
        if len(sys.argv) < 2:
            sys.exit('请按照要求,指定模块名称:应用名称,例如 module:callable')
    
        #获取module:callable
        appPath = sys.argv[1]
        #根据冒号切割为module和callable
        module, application = appPath.split(':')
        print("module=%s"%module)
        #添加路径套sys.path
        sys.path.insert(0, pythonRoot)
        #动态导入module变量中指定的模块
        module = __import__(module)
        #获取module变量中制定的模块的application变量指定的属性
        application = getattr(module, application)
        httpd = makeServer(serverAddr, application)
        print('WSGIServer: Serving HTTP on port {port} ...
    '.format(port=PORT))
        httpd.serveForever()
    
    if __name__ == '__main__':
        main()

    2、应用程序代码ctime.py

    #coding:utf-8
    
    
    import time
    
    
    def app(environ, start_response):
        status = "200 OK"
    
        response_headers = [
            ("Content-Type", "text/plain")
        ]
    
        start_response(status, response_headers)
        return [str(environ)+'--->%s
    '%time.ctime()]

    3、命令行执行代码 

    4、浏览器运行结果

  • 相关阅读:
    python 发邮件乱码
    膳魔师杯使用注意事项
    了解指针,分分钟的事情 C++筆記--指針
    海淘攻略
    【转】Cocos2dx.3x入门三部曲
    在Windows7上搭建Cocos2d-x 3.2alpha0开发环境
    黑苹果 MAC OS X 10.10.2 安装流程
    Linux 下如何查找木马并处理
    js如何判断访问是来自搜索引擎(蜘蛛人)还是直接访问
    泰*网 Centos 一些命令
  • 原文地址:https://www.cnblogs.com/Se7eN-HOU/p/11053182.html
Copyright © 2020-2023  润新知