zoukankan      html  css  js  c++  java
  • WSGI-mini-web框架服务器

    前期准备:

    安装python环境
    安装pycharm
    安装MySQL数据库
    安装pymsql
    创建一个学生表,存入数据

    说明:
    我们只是实现一个非常简单的web服务,前端页面不会专门做页面文件,会在代码中以具体命令的形式形成文件样式。

    服务器的功能:

    1、show.html显示student表中的数据,点击页面内的修改按钮,会跳转到change.html页面修改内容

    2、change.html修改student表中数据,将学生姓名由“张三”改为“李四”,点击页面内的"show page"会重新跳转到显示学生信息页面重新显示修改后的学生信息

    创建表

    create table student(
        id int primary key,
        sname varchar(50) not null,
        sex char(5) not null
    );
    

      

    原始表数据

    一、创建tcp服务器tcpWebServer.py

    服务器需要实现多线程的访问,采用面向对象的思想,创建一个服务器类。采用wsgi的思想,需要在服务器类中预先设置一个set_response方法,供框架代码中application的调用

    Tcp服务器类创建流程如下:

    因为多线程中都需要使用到套接字创建、ip和port的绑定,以及监听(listen),所以我们设计类的时候将这几部分设置为对象属性,直接在初始化方法中创建

    创建__init__方法

    1. 创建套接字绑定ip和port:使用命令bind()
    2. Listen使套接字变为可以被动链接:使用命令listen()

    创建服务器处理请求/发送请求方法

    1. 接收客户端传送的request数据
    2. 因为前端发送的数据是url地址所以需要处理url地址的代码
    3. 设置伪静态的url地址
    4. 发送response返回给前端

    创建set_response函数

    创建运行函数

     1 import multiprocessing
     2 import re
     3 import socket
     4 from 简单web服务实现 import web_frame
     5  
     6  
     7 class MSGIServer:
     8     def __init__(self):
     9         """初始化方法,完成套接字创建、ip和port绑定、listen监听"""
    10         # 创建套接字
    11         self.tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    12         self.tcp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    13  
    14         # 绑定ip和端口,使用方法bind((ip, 端口)),注意bind方法需要入参一个元组
    15         # 自己编写的代码不要使用1024以内的端口号
    16         self.tcp_socket.bind(('', 7890))
    17  
    18         #监听
    19         self.tcp_socket.listen(128)
    20  
    21  
    22     def client_server(self, new_socket):
    23         """处理和客户端之间数据的交互:接收recv/发送send"""
    24         # 接收客户端发送过来的请求
    25         # 使用方法recv(),数字参数是指定长度
    26         # decode()方法实现解码,参数为编码格式,因为为使用的window系统,所以使用gbk格式
    27         request = new_socket.recv(1024).decode('gbk')
    28         print(str(request).splitlines()[0])
    29         # 使用正则提取请求url地址的后缀名
    30         # group()表示分组匹配
    31         file_name = re.match('.*/.*.([a-z]*)sH', str(request).splitlines()[0]).group(1)
    32         # 使用正则提取请求的url地址,用于后面代码中进行匹配
    33         page_name = re.match('.*/(.*)sH', str(request).splitlines()[0]).group(1)
    34         # 返回数据给客户端
    35         # 根据请求的url地址的不同,返回不同的数据,伪静态(.html)内容是目标内容,否则一律返回404
    36         if not file_name.endswith('html'):
    37             response = "HTTP/1.1 200 OK 
    "
    38             response += '
    '
    39             response += "<h1>404 NOT FOUND</h1>"
    40             new_socket.send(response.encode('gbk'))
    41         else:
    42             # 创建字典,后面调用application函数作为参数传递
    43             env = dict()
    44             env['path'] = page_name
    45             print('--->page_name=%s<---' % page_name)
    46             # 调用框架模块中的application方法,传入url信息,确定执行的命令
    47             body = web_frame.application(env, self.set_response)
    48             # print('--->body=%s<---' % body)
    49             # response = "HTTP/1.1 200 OK 
    "
    50             header = 'HTTP/1.1 %s
    ' % self.status
    51             for temp in self.header:
    52                 header += '%s:%s' % (temp[0], temp[1])
    53                 header += '
    '
    54             response = header + '
    ' + body
    55  
    56             new_socket.send(response.encode('utf-8'))
    57         new_socket.close()
    58  
    59     # 设置请求头
    60     def set_response(self, status, headers):
    61         self.status = status
    62         self.header = headers
    63  
    64  
    65     def run_forver(self):
    66         """实现web服务器"""
    67         while True:
    68             # 4、等待新客户端的链接 accept
    69             new_socket, socket_address = self.tcp_socket.accept()
    70             # 5、为新客户端服务,独立为服务的方法处理接收和发送数据(request
    esponse)
    71             p = multiprocessing.Process(target=self.client_server, args=(new_socket,))
    72             # client_server(new_socket)
    73             p.start()
    74             new_socket.close()
    75         self.tcp_socket.close()
    76  
    77  
    78 def main():
    79     msgi_server = MSGIServer()
    80     msgi_server.run_forver()
    81  
    82 if __name__ == '__main__':
    83     main()

    二、创建框架web_frame.py

    1. 创建闭包
    2. 创建两个函数show(显示学生信息)、change(修改学生信息)
    3. 创建application函数
     1 import time
     2 import pymysql
     3 import logging
     4  
     5 URL_FUNC_DICT = dict()
     6 func_list = list()
     7  
     8  
     9 def route(url):
    10     """创建路由闭包:
    11         实现url地址的路由,即根据装饰器填入的url信息执行装饰器所装饰的方法
    12     """
    13     def set_func(func):
    14         URL_FUNC_DICT[url] = func
    15  
    16         def call_func():
    17             func()
    18         return call_func
    19     return set_func
    20  
    21  
    22 @route('show.html')
    23 def show():
    24     """登录网页"""
    25     sql = "select * from student;"
    26     # 链接MySQL服务器
    27     conn = pymysql.connect(host='127.0.0.1', user='wang', password='123456', database='jingdong', port=3306, charset='utf8')
    28     cur = conn.cursor()
    29     cur.execute(sql)
    30     # 获取查询到的数据
    31     data = cur.fetchone()
    32     print(data)
    33     cur.close()
    34     conn.close()
    35     # 构建一个网页内容
    36     table = """<html>
    37             <head>
    38             <meta charset="utf-8">
    39             <title>学生信息</title>
    40             </head>
    41             <body>
    42             <tr>
    43                     <td>%s</td>
    44                     <td>%s</td>
    45                     <td>%s</td>
    46                     <td>
    47                         <a href="/change.html"><input type="button" value="修改"></a>
    48                     </td>
    49                     </tr>
    50             </body>
    51             </html>"""
    52     # 将数据库查询到的数据拼接到网页内容中
    53     res = table % (str(data[0]), data[1], data[2])
    54     # return cur.fetchone()[0]+str
    55     return res
    56  
    57  
    58 @route('change.html')
    59 def change():
    60     """修改数据页面"""
    61     # 链接MySQL服务器
    62     sql = "update student set sname='李四';"
    63     # 创建数据库链接对象
    64     conn = pymysql.connect(host='127.0.0.1', user='wang', password='123456', database='jingdong', port=3306,
    65                            charset='utf8')
    66     # 创建游标
    67     cur = conn.cursor()
    68     # 执行sql命令
    69     lines = cur.execute(sql)
    70     # 提交数据
    71     conn.commit()
    72     cur.close()
    73     conn.close()
    74     return "<a href="show.html">show page</a>"
    75  
    76  
    77 # 服务器代码调用执行的代码
    78 # 遵照wsgi协议,框架中需要存在一个application(字典, 函数引用)函数
    79 # 字典,用来传入前端所提交的信息   引用的函数时服务器创建的封装响应头的函数
    80 def application(environ, start_response):
    81     # 调用tcpWebServer模块中的设置相应函数,设置响应头
    82     start_response('200 OK', [('Context-Type', 'text/html')])
    83     # 获取前端传入的字典中的路径,即url地址
    84     page_name = environ['path']
    85     # 设置日志
    86     logging.basicConfig(level=logging.INFO,
    87                         filename='./log.txt',
    88                         filemode='a',
    89                         # format表示日志文件中显示的格式
    90                         # astime时间  写入文件名   第几行的日志信息    日志等级    打印的信息
    91                         format='%(asctime)s-%(filename)s[line:%(lineno)d]-%(levelname)s:%(message)s'
    92                         )
    93     logging.info('访问的是:%s' % page_name)
    94     if page_name in URL_FUNC_DICT.keys():
    95         return URL_FUNC_DICT[page_name]()
    96     else:
    97         return 'not Found'
    98  

    运行效果

    代码运行,浏览器输入"localhost:7890/show.html"查看学生的信息

     

    点击“修改”按钮会跳转到change.html页面

     

    再点击“show page”链接会重新跳转回show.html页面,显示修改后的学生信息

     

    数据库中的数据也已经同步更新

     

    代码目录下已经生成了日志文件

     

    内容为我们设定的显示内容

     

    以上是一个非常简易的web服务,后续我们会使用到Django框架来详细设计一个完整的web服务

    超全面的测试IT技术课程,0元立即加入学习!有需要的朋友戳:
    腾讯课堂测试技术学习地址

    作者:树山
    出处: https://www.cnblogs.com/treemountain/
    欢迎转载,但未经作者同意请保留此段声明,并在文章页面明显位置给出原文链接。
  • 相关阅读:
    c# winform 应用编程代码总结 5
    c# winform 应用编程代码总结 6
    C语言 如何隐藏DOS窗口
    c# winform 应用编程代码总结 13
    c# winform 应用编程代码总结 8
    c# winform 应用编程代码总结 7
    c# winform 应用编程代码总结 10
    Ext grid改变行背景颜色 和改变行字体颜色
    我的博客学习记录一箩筐(每天更新)
    New version of wxDesigner based on wxWidgets pre3.0 released
  • 原文地址:https://www.cnblogs.com/treemountain/p/12505955.html
Copyright © 2011-2022 走看看