首页 > 编程语言 > 详细

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

时间:2019-06-19 18:51:15      阅读:120      评论:0      收藏:0      [点我收藏+]

一、浏览器请求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\r\n"
                responseHeaderLines += "\r\n"
                responseBody = "====sorry ,file not found===="
            else:
                responseHeaderLines = "HTTP/1.1 200 OK\r\n"
                responseHeaderLines += "\r\n"
                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(\r\n)
        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}\r\n.format(status=status)
            #response的其他头信息
            for header in response_headers:
                response += {0}: {1}\r\n.format(*header)
            #添加一个换行,用来和body进行分开
            response += \r\n
            #添加发送的数据
            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} ...\n.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\n%time.ctime()]

3、命令行执行代码 

技术分享图片

4、浏览器运行结果

技术分享图片

 

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

原文:https://www.cnblogs.com/Se7eN-HOU/p/11053182.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!