当前位置: 移动技术网 > IT编程>脚本编程>Python > python网络-动态Web服务器案例(30)

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

2019年06月20日  | 移动技术网IT编程  | 我要评论

2828商机网,让生命充满爱下载,kan kan

一、浏览器请求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 + "/"
            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             # /
        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、浏览器运行结果

 

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网