WSGI服务器

  1 import re
  2 from pymysql import connect
  3 import urllib.parse
  4 import logging
  5 
  6 
  7 URL_FUNC_DICT = dict()
  8 
  9 def open_mysql():
 10     # 创建connect连接
 11     conn = connect(host='localhost',port=3306,user='root',password='m',database='stock',charset='utf8')
 12     # 获得cursor对象
 13     cs = conn.cursor()
 14     return conn, cs
 15 
 16 def close_mysql(conn, cs):
 17     # 关闭连接、对象
 18     cs.close()
 19     conn.close()
 20 
 21 def route(path_info):
 22     '''装饰器:添加方法-路径到字典'''
 23     def set_func(func):
 24         URL_FUNC_DICT[path_info] = func
 25         def call_func(*args, **kwargs):
 26             return func(*args, **kwargs)
 27         return call_func
 28     return set_func
 29 
 30 @route(r"/index.html")
 31 def index(ret):
 32     # 打开、读取网页
 33     with open("./templates/index.html", encoding="utf-8") as f:
 34         content = f.read()
 35     # 打开数据库
 36     conn, cs = open_mysql()
 37     # 执行sql语句
 38     cs.execute("select * from info;")
 39     # 读取数据库数据
 40     stock_infos = cs.fetchall()
 41     # 关闭数据库
 42     close_mysql(conn, cs)
 43     # 数据库数据替换模板数据
 44     tr_template = """<tr>
 45         <td>%s</td>
 46         <td>%s</td>
 47         <td>%s</td>
 48         <td>%s</td>
 49         <td>%s</td>
 50         <td>%s</td>
 51         <td>%s</td>
 52         <td>%s</td>
 53         <td>
 54             <input type="button" value="添加" id="toAdd" name="toAdd" systemidvaule="%s">
 55         </td>
 56         </tr>
 57     """
 58     html = ""
 59     for line_info in stock_infos:
 60         html += tr_template % (line_info[0],line_info[1],line_info[2],line_info[3],line_info[4],line_info[5],line_info[6],line_info[7], line_info[1])
 61     return re.sub(r"{%content%}", html, content)
 62 
 63 @route(r"/center.html")
 64 def center(ret):
 65     # 打开读取网页
 66     with open("./templates/center.html", encoding="utf-8") as f:
 67         content = f.read()
 68     # 打开数据库
 69     conn, cs = open_mysql()
 70     # 执行sql语句
 71     cs.execute("select i.code, i.short, i.chg, i.turnover, i.price, i.highs, f.note_info from info as i inner join focus as f on i.id = f.info_id;")
 72     # 读取sql语句结果
 73     stock_infos = cs.fetchall()
 74     # 关闭数据库
 75     close_mysql(conn, cs)
 76     tr_template = """
 77         <tr>
 78             <td>%s</td>
 79             <td>%s</td>
 80             <td>%s</td>
 81             <td>%s</td>
 82             <td>%s</td>
 83             <td>%s</td>
 84             <td>%s</td>
 85             <td>
 86                 <a type="button" class="btn btn-default btn-xs" href="/update/%s.html"> <span class="glyphicon glyphicon-star" aria-hidden="true"></span> 修改 </a>
 87             </td>
 88             <td>
 89                 <input type="button" value="删除" id="toDel" name="toDel" systemidvaule="%s">
 90             </td>
 91         </tr>
 92     """
 93     # 用数据库内容替换模板数据
 94     html = ""
 95     for stock_info in stock_infos:
 96         html += tr_template % (stock_info[0], stock_info[1], stock_info[2], stock_info[3],stock_info[4], stock_info[5], stock_info[6], stock_info[0], stock_info[0])
 97     return re.sub(r"{%content%}", html, content)
 98 
 99 @route(r"^/add/(d+).html$")
100 def add_focus(ret):
101     '''添加股票'''
102     # 获取股票代码
103     stock_code = ret.group(1)
104     # 打开数据库,查询股票代码
105     conn, cs = open_mysql()
106     sql = "select * from info where code = %s;"
107     cs.execute(sql, (stock_code,))
108     # 股票代码不在数据库中
109     if not cs.fetchall():
110         # 返回提示
111         close_mysql(conn, cs)
112         return "没有这只股票代码,请收下留情。。"
113     # 判断股票代码是否已存在于focus表数据库中
114     sql = "select * from info as i inner join focus as f on i.id = f.info_id where i.code = %s"
115     cs.execute(sql, (stock_code,))
116     # 已存在于focus表
117     if cs.fetchall():
118         close_mysql(conn, cs)
119         return "已成功关注,请勿重复关注。。"
120     # 不存在于focu表
121     # 执行sql语句添加股票代码到focus表
122     sql = "insert into focus(info_id) select id from info where code = %s;"
123     cs.execute(sql, (stock_code))
124     conn.commit()
125     # 关闭数据库
126     close_mysql(conn, cs)
127     return "关注成功。。"
128 
129 @route(r"^/del/(d+).html$")
130 def del_focus(ret):
131     '''取消关注股票'''
132     stock_code = ret.group(1)
133     print(stock_code)
134     conn, cs = open_mysql()
135     sql = "select * from focus as f inner join info as i on i.id = f.info_id where i.code = %s;"
136     cs.execute(sql, (stock_code,))
137     # 股票代码不存在于focus表
138     if not cs.fetchall():
139         close_mysql(conn, cs)
140         return "未曾关注,谈何取消。。"
141     sql = "delete from focus where info_id = (select id from info where code = %s);"
142     cs.execute(sql, (stock_code,))
143     conn.commit()
144     close_mysql(conn, cs)
145     return "已成功取关注。。"
146 
147 @route(r"/update/(d+).html")
148 def update_info(ret):
149     '''更新数据'''
150     # 获取股票代码
151     stock_code = ret.group(1)
152     # 打开数据库,查询股票代码
153     conn, cs = open_mysql()
154     sql = "select * from info where code = %s;"
155     cs.execute(sql, (stock_code,))
156     # 股票代码不在数据库中
157     if not cs.fetchall():
158         # 返回提示
159         close_mysql(conn, cs)
160         return "没有这只股票代码,请收下留情。。"
161     # 判断股票代码是否已存在于focus表数据库中
162     sql = "select * from info as i inner join focus as f on i.id = f.info_id where i.code = %s"
163     cs.execute(sql, (stock_code,))
164     # 已存在于focus表
165     if not cs.fetchall():
166         close_mysql(conn, cs)
167         return "没有关注,请勿输入备注。。"
168     # 打开网页
169     with open("./templates/update.html", encoding="utf-8") as f:
170         content = f.read()
171     # 替换模板,回传数据
172     content = re.sub(r"{%note_info%}","请输入修改内容", content)
173     return re.sub(r"{%code%}", stock_code, content)
174     # return "更新数据成功。。"
175 
176 @route(r"/update/(d+)/(.*).html")
177 def save_update(ret):
178     stock_code = ret.group(1)
179     new_info = ret.group(2)
180     new_info = urllib.parse.unquote(new_info)
181     # 打开数据库,查询股票代码
182     conn, cs = open_mysql()
183     sql = "select * from info where code = %s;"
184     cs.execute(sql, (stock_code,))
185     # 股票代码不在数据库中
186     if not cs.fetchall():
187         # 返回提示
188         close_mysql(conn, cs)
189         return "没有这只股票代码,请收下留情。。"
190     # 判断股票代码是否已存在于focus表数据库中
191     sql = "select * from info as i inner join focus as f on i.id = f.info_id where i.code = %s"
192     cs.execute(sql, (stock_code,))
193     # 不存在于focu表
194     if not cs.fetchall():
195         close_mysql(conn, cs)
196         return "未曾关注,请勿修改。。"
197     # 已存在于focus表
198     # 执行sql语句添加股票代码到focus表
199     sql = "update focus set note_info=%s where info_id = (select id from info where code=%s);"
200     cs.execute(sql, (new_info, stock_code))
201     conn.commit()
202     # 关闭数据库
203     close_mysql(conn, cs)
204     return "修改成功。。"
205 
206 def application(env, start_header):
207     start_header("200 OK", [("Content-type", "text/html;charset=utf-8")])
208     # 获取请求文件信息
209     file_name = env["PATH_INFO"]
210     file_name = urllib.parse.unquote(file_name)
211     # 日志设定
212     # 创建logger
213     logger = logging.getLogger()
214     logger.setLevel(logging.DEBUG)
215     # 创建一个handler,用于写入文件
216     logfile = "./log.txt"
217     fh = logging.FileHandler(logfile,mode='a')
218     fh.setLevel(logging.INFO)
219     # 创建一个handler,用于输出控制台
220     ch = logging.StreamHandler()
221     ch.setLevel(logging.WARNING)
222     # 定义日志输出格式
223     formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")
224     fh.setFormatter(formatter)
225     ch.setFormatter(formatter)
226     # 将logger添加到handler中
227     logger.addHandler(fh)
228     logger.addHandler(ch)
229     logger.info("客户访问:%s" % file_name)
230     try:
231         for url, func in URL_FUNC_DICT.items():
232             ret = re.match(url, file_name)
233             if ret:
234                 return func(ret)
235         else:
236             logger.warning("请求错误。file(%s) not found" % file_name)
237             return "请求错误。file(%s) not found" % file_name
238     except Exception as e:
239         logger.warning("程序异常。错误信息:%s" % e)
240         return "请求错误。logger错误信息:%s" % e
  1 import sys
  2 import re
  3 import socket
  4 import multiprocessing
  5 
  6 class WSGIServer(object):
  7     '''服务器运行对象'''
  8     def __init__(self, port, app, static_path):
  9         '''对象初始化'''
 10         # 创建套接字
 11         self.tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 12         self.tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
 13         # 绑定端口 IP
 14         self.tcp_server_socket.bind(("", port))
 15         # 设置监听套接字
 16         self.tcp_server_socket.listen(128)
 17         # web框架调用方法
 18         self.application = app
 19         # 静态网页存放地址
 20         self.static_path = static_path
 21 
 22     def client_serve(self, client_socket):
 23         '''为浏览器实现具体服务'''
 24         # 获取浏览器请求
 25         request = client_socket.recv(1024).decode("utf-8")
 26         request_lines = request.splitlines()
 27         # 解析浏览器请求
 28         ret = re.match(r"[^/]+(/[^ ]*)", request_lines[0])
 29         file_name = ""
 30         if ret:
 31             file_name = ret.group(1)
 32             if file_name == "/":
 33                 file_name = "/index.html"
 34         # print("file_nema:", file_name)
 35         # 如果为静态页面请求(非html请求)
 36         if not file_name.endswith(".html"):
 37             # 打开请求页面
 38             try:
 39                 with open(self.static_path + file_name, "rb") as f:
 40                     response_body = f.read()
 41             # 打开页面失败
 42             except:
 43                 response_body = "file not found"
 44                 response_header = "HTTP/1.1 404 FILE NOT FOUND
"
 45                 response_header += "
"
 46                 response = response_header + response_body
 47                 client_socket.send(response.encode("utf-8"))
 48             # 打开页面成功
 49             else:
 50                 response_header = "HTTP/1.1 200 OK
"
 51                 response_header += "
"
 52                 response = response_header.encode("utf-8") + response_body
 53                 client_socket.send(response)
 54         # 如果为动态页面请求
 55         else:
 56             env = dict()
 57             env["PATH_INFO"] = file_name
 58             # print(file_name)
 59             # 调用web框架方法,处理页面
 60             response_body = self.application(env, self.set_headers)
 61 
 62             response_header = "HTTP/1.1 %s 
" % self.status
 63             for header in self.header_list:
 64                 response_header += "%s:%s
" %(header[0],header[1])
 65             response_header += "
"
 66 
 67             response = response_header + response_body
 68             client_socket.send(response.encode("utf-8"))
 69         # 关闭套接字
 70         client_socket.close()
 71 
 72     def set_headers(self, status, header_list):
 73         '''存放web框架请求头信息'''
 74         self.status = status
 75         self.header_list = header_list
 76 
 77     def fun_forever(self):
 78         '''服务器对象流程控制'''
 79         while True:
 80             # print("等待浏览器连接")
 81             client_socket, client_addr = self.tcp_server_socket.accept()
 82             # 利用多进程实现多任务操作
 83             # print("创建子线程")
 84             p = multiprocessing.Process(target=self.client_serve, args=(client_socket,))
 85             p.start()
 86             client_socket.close()
 87 
 88 def error_msg():
 89     print("服务器开启失败,请按以下方式输入")
 90     print("python xxx.py 8080 mini_frame:application")
 91 
 92 def main():
 93     '''实现主体流程控制'''
 94     # # 获取服务器端口、web_frame框架地址、方法名
 95     # # 如果程序调用参数为3,输入正确
 96     # if len(sys.argv) == 3:
 97     #     # 参数输入方式正确
 98     #     try:
 99     #         port = int(sys.argv[1])
100     #         frame_app_name = sys.argv[2]
101     #     # 参数输入方式错误
102     #     except:
103     #         error_msg()
104     # # 如果不为3,调用方法错误,输出提示
105     # else:
106     #     error_msg()
107     port = 8080
108     frame_app_name = "mini_frame:application"
109     # 打开配置文件,获取静态、动态文件夹地址
110     with open("web_server.conf") as f:
111         conf_info = eval(f.read())
112     dynamic_path = conf_info["dynamic_path"]
113     sys.path.append(dynamic_path)
114     # 获取框架名、方法名
115     ret = re.match(r"([^:]+):(.*)", frame_app_name)
116     if ret:
117         frame_name = ret.group(1)
118         app_name = ret.group(2)
119         # print("app",app_name)
120     else:
121         error_msg()
122     # 导入web_frame框架
123     frame = __import__(frame_name)
124     # 导入app方法
125     app = getattr(frame, app_name)
126     # print("创建WSGI对象")
127     # 创建WSGI对象
128     wsgi_server = WSGIServer(port, app, conf_info["static_path"])
129     # 调用其run_forever方法,使流程不断运行
130     wsgi_server.fun_forever()
131 
132 if __name__ == "__main__":
133     main()
原文地址:https://www.cnblogs.com/sure-feng/p/10427603.html