1. 程式人生 > >python學習之實現簡單的miniWeb伺服器

python學習之實現簡單的miniWeb伺服器

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

提供了兩個動態資料的網頁,一個事模擬股票資訊的網頁,一個是模擬了個人中心中收藏股票資訊的網頁,兩個網頁均在載入是訪問了資料庫,獲取資料庫中的資料。其他的功能沒有新增,沒錯,就是因為不會...