当前位置: 首页 > 工具软件 > MiniWeb > 使用案例 >

python学习之实现简单的miniWeb服务器

臧友樵
2023-12-01

奉上完整的小项目的代码:我的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

提供了两个动态数据的网页,一个事模拟股票信息的网页,一个是模拟了个人中心中收藏股票信息的网页,两个网页均在加载是访问了数据库,获取数据库中的数据。其他的功能没有添加,没错,就是因为不会...

 类似资料: