python學習之實現簡單的miniWeb伺服器
阿新 • • 發佈:2018-12-11
webServer部分:
#!/usr/bin/venv python3 # coding: utf-8 import socket import multiprocessing import re import dynamic.WebFrame as WebFrame class WebServer(object): def __init__(self): self.__tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.__tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) self.__tcp_server_socket.bind(('', 7000)) self.__tcp_server_socket.listen(128) def service_client(self, new_socket): request = new_socket.recv(4096).decode('utf-8') request_lines = request.splitlines() # for t in request_lines: # print(t) file_name = "" ret = re.match(r"[^/]+(/[^ ]*)", request_lines[0]) if ret: file_name = ret.group(1) print("FileName:" + file_name) if file_name == "/": file_name = "/index.html" if file_name.endswith(".html"): # 這裡動態的處理 env = {'PATH_INFO':file_name} # 呼叫框架中的application函式,進行通訊 response_body = WebFrame.application(env, self.__start_response) # 準備相應行 response_line = "HTTP/1.1 %s\r\n" % self.__status # 準備響應頭 response_head = "Server: MiniWebServer3.0\r\n" # 拼接響應頭資料 for tmp in self.__params: response_head += "%s:%s\r\n" % tmp # 拼接響應報文 response_data = response_line + response_head + "\r\n" + response_body # 傳送報文 new_socket.send(response_data.encode("utf-8")) else: try: with open("./static" + file_name, 'rb') as file: file_data = file.read() except: # 如果沒有找到 response_line = "HTTP/1.1 404 NOT FOUND\r\n" response_head = "\r\n" response_body = "<h1>404 Not Found!!</h1>" response_data = response_line + response_head + response_body new_socket.send(response_data.encode("utf-8")) else: # 如果找到對應的檔案讀取並返回 response_line = "HTTP/1.1 200 OK\r\n" response_head = "\r\n" response = response_line + response_head new_socket.send(response.encode("utf-8")) response_body = file_data new_socket.send(response_body) # 關閉套接字 new_socket.close() def __start_response(self, status, params): """ 準備一個回撥函式 :param status: 用來儲存狀態資訊(字串) :param params: 用來儲存響應資訊(列表包含元組表示鍵值關係) :return: """ self.__status = status self.__params = params def start(self): while True: new_socket, ip_port = self.__tcp_server_socket.accept() process = multiprocessing.Process(target=self.service_client, args=(new_socket, )) process.start() if __name__ == '__main__': server = WebServer() server.start()
WebFrame部分程式碼:
#!/usr/bin/venv python3 # coding: utf-8 import re from pymysql import * # 定義路由表 route_table = {} def application(environ, start_response): """ WSGI介面函式,實現伺服器與框架的的通訊,在框架中定義 :param environ: 要被動態處理的(字典) :param start_response: 回撥函式->用做與伺服器程式的傳值(函式) :return: """ # 獲取傳入的字典 file_name = environ['PATH_INFO'] # 準備一個函式,來執行相應的操作 function = other if file_name in route_table: function = route_table[file_name] # 執行function函式,返回相應體資料 file_content = function() # 通過傳入的函式,來實現回撥 start_response("200 OK", [("Content-Type",'Text/html;charsetutf-8')]) # 講body返回 response_body = file_content return response_body # 定義一個帶參的裝飾器,用來給路由表新增鍵值關係 def router(url): def set_fun(func): def wrapper(*args, **kwargs): return func(*args, **kwargs) # 給路由表新增關係 route_table[url] = wrapper return wrapper return set_fun def other(): file_content = '<h1>Other Page Run ...</h1>' return file_content # ###############以下為web應用的動態處理函式############################## @router('/center.html') def center(): # 利用模板將個人中心頁面展示出來 # 拼接模板路徑 path = './templates/center.html' # 讀取模板內容 with open(path, 'r') as f: file_content = f.read() # 準備資料 row_str = """ <tr> <td>%s</td> <td>%s</td> <td>%s</td> <td>%s</td> <td>%s</td> <td>%s</td> <td>%s</td> <td> <a type="button" class="btn btn-default btn-xs" href="/update/000426.html"> <span class="glyphicon glyphicon-star" aria-hidden="true"></span> 修改 </a> </td> <td> <input type="button" value="刪除" id="toDel" name="toDel" systemidvaule="000426"> </td> </tr> """ # 連線資料庫,從資料庫裡去讀取資料,填充模板中的佔位符 conn = Connection(host='localhost',port=3306,database='stock',user='root',password="password",charset='utf8') cur = conn.cursor() sql_str = ''' select info.code,info.short,info.chg,info.turnover,info.price,info.highs,focus.note_info from info inner join focus on info.id = focus.info_id ''' cur.execute(sql_str) result = cur.fetchall() cur.close() conn.close() # 多整幾條 all_data = '' for t in result: all_data += row_str % (t[0],t[1],t[2],t[3],t[4],t[5],t[6]) # 使用正則替換模板中的變數 file_content = re.sub(r'\{%content%\}', all_data, file_content) return file_content @router('/index.html') def index(): # 在這裡,具體來處理相應返回的資料,並且將資料加到模板檔案中,一起返回 # 拼接模板檔案的路徑 path = './templates/index.html' # 讀取模板檔案的內容 with open(path, 'r') as f: file_content = f.read() # 準備一條資料 row_str = """ <tr> <td>%s</td> <td>%s</td> <td>%s</td> <td>%s</td> <td>%s</td> <td>%s</td> <td>%s</td> <td>%s</td> <td> <input type="button" value="新增" id="toAdd" name="toAdd" systemidvaule="%s"> </td> </tr> """ # 連線資料庫,去讀取資料 conn = Connection(host='localhost',port=3306,database='stock',user='root',password='password',charset='utf8') cur = conn.cursor() sql_str = ''' select * from info; ''' cur.execute(sql_str) result = cur.fetchall() cur.close() conn.close() # 拼接幾條資料 all_data = '' for t in result: all_data += row_str % (t[0],t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[1]) # '%s:%s' %('a','b) # 將拼接好的資料,替換到到模板中去,替換 {%content%} file_content = re.sub(r'\{%content%\}', all_data, file_content) return file_content
提供了兩個動態資料的網頁,一個事模擬股票資訊的網頁,一個是模擬了個人中心中收藏股票資訊的網頁,兩個網頁均在載入是訪問了資料庫,獲取資料庫中的資料。其他的功能沒有新增,沒錯,就是因為不會...