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 \r\n"
38             response += '\r\n'
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 \r\n"
50             header = 'HTTP/1.1 %s\r\n' % self.status
51             for temp in self.header:
52                 header += '%s:%s' % (temp[0], temp[1])
53                 header += '\r\n'
54             response = header + '\r\n' + 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\response)
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服务

猜你喜欢

转载自www.cnblogs.com/monkey4king/p/12467684.html