python miniwebフレームワークの実装


ユーザーはブラウザを通じてwebサーバーに要求を送信し、サーバーは要求資源によって異なる戻り方式を採用し、ブラウザが要求したのは静的資源で、サーバーは直接応答資源に戻り、ブラウザが要求したのは動的資源で、サーバーは要求をフレームワークに送信し、フレームワークはテンプレートを呼び出し、要求データとテンプレートを結合してサーバーに戻る必要がある.サーバはテンプレートを応答体としてブラウザに送信します.
ブラウザは応答体を読み取り、画像などの静的リソースがあれば、ブラウザは引き続きサーバにリソース要求を送信し、サーバは直接静的リソースに戻り、すべてのリソース要求が完了すると、ブラウザは最終ページをユーザーに返す.
Webサーバの実装
HttpServer.py
import socket
import re
import gevent
import sys
import hframe_flask_stock
from gevent import monkey

monkey.patch_all()


class HttpServer():
    # 1       
    def __init__(self,port=80):
        tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 2       
        tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
        # 3        ,    
        socket_address = ("", port)
        tcp_server_socket.bind(socket_address)
        # 4     ,             128(          )
        tcp_server_socket.listen(128)
        # 5            
        self.tcp_server_socket = tcp_server_socket

    def start(self):
        # 6        ,          
        while True:
            # 7     ,            
            new_client_socket,ip_port = self.tcp_server_socket.accept()
            print("      ")
            g1 = gevent.spawn(self.request_handler,new_client_socket)
            #           ,           
            # g1.join()

    def request_handler(self,new_client_socket):
        # 8        ,     
        recv_data = new_client_socket.recv(1024)
        if not recv_data:
            print("        ")
            new_client_socket.close()
            return
        #   
        request_text = recv_data.decode()
        print("     ",request_text)
        #      \r
, request_list = request_text.split('\r
') print(" ",request_list) ret = re.search(r"\s(.*)\s", request_list[0]) # if not ret: print(" ") new_client_socket.close() return # path_info = ret.group(1) print(" ",path_info) if path_info == '/': path_info = '/index.html' # env = { "PATH_INFO": path_info } # .xxx .html if path_info.endswith(".html"): status, headers, body = hframe_flask_stock.app(env) # response_line = "HTTP/1.1 %s\r
" % status response_head = "" for header in headers: response_head += "%s: %s\r
" % header response_data = response_line + response_head + "\r
" + body # response_data = response_data.encode() new_client_socket.send(response_data) new_client_socket.close() else: # 9 # 9.1 response_line = "" # 9.2 response_head = "Server:py1.0\r
" # 9.3 response_blank = "\r
" # 9.4 # , try: with open("static"+path_info, "rb") as file: # response_content response_content = file.read() except Exception as e: response_line = "HTTP/1.1 404 Not Found\r
" response_content = "Error! %s" % str(e) # response_content = response_content.encode() else: response_line = "HTTP/1.1 200 OK\r
" finally: # response_data = (response_line + response_head + response_blank).encode() + response_content # 11 new_client_socket.send(response_data) # 12 new_client_socket.close() def main(): # 80 # HttpServer httpserver = HttpServer() # httpserver.start() if __name__ == '__main__': main()

シミュレーションflaskフレームワーク
 hframe_flask_stock.py
flaskは,アクセラレータファクトリ方式で経路と関数を対応させ,ルーティングリストに組み込む.
使用するデータベースはstock_ですdbは、データベース内のinfoテーブルとfocusテーブルを使用してデータを提供します.
import time
import pymysql

#          
Env = {}

mysql_connect = pymysql.connect(host='127.0.0.1', port=3306, user='root', db='stock_db', password='mysql',charset='utf8')
cursor = mysql_connect.cursor()

#     
def route(url):
    def wrapper(func):
        Env[url] = func
        def inner():
            pass
    return wrapper


@route("/gettime.html")
def get_time():
    return time.ctime()

@route("/index.html")
def get_index():
    with open("./template/index.html", 'r') as f:
        f_content = f.read()

    sql = "select * from info"
    cursor.execute(sql)
    cursor_content = cursor.fetchall()
    # print(str(cursor_content))

    mysql_content = ""
    for line in cursor_content:
        print(line)
        data_str = """
                
        	    %s
        	    %s
        	    %s
        	    %s
        	    %s
        	    %s
        	    %s
        	    %s
        	    
        	    
                """ % line
        mysql_content += data_str
    f_content = f_content.replace("{%content%}", mysql_content)
    return f_content

@route("/center.html")
def get_center():
    with open("./template/center.html", 'r') as f:
        f_content = f.read()

    sql = "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"
    cursor.execute(sql)
    mysql_content = ""
    for line in cursor.fetchall():
        data_str = """
                    
        	    %s
        	    %s
        	    %s
        	    %s
        	    %s
        	    %s
        	    %s
        	      
        	     
            
                """ % line
        mysql_content += data_str
    f_content = f_content.replace("{%content%}", mysql_content)
    return f_content

def app(env):
    #   env     web              
    print("          ")
    # print("Env",Env)
    path_info = env["PATH_INFO"]
    if path_info in Env:
        return "200 ok", [('Server', 'py1.0')], Env[path_info]()
    else:
        #       
        return "404 Not Forund", [('Server','py1.0')], "this is test frame"

# print(get_index())

シミュレーションdjangoフレームワーク
djangoフレームワークは、経路と関数の対応関係をルーティングリストに手動で追加します.
import time


def get_time():
    return time.ctime()

def get_index():
    with open("./template/index.html", 'r') as f:
        f_content = f.read()

    mysql_content = "       "
    f_content = f_content.replace("{%content%}", mysql_content)
    return f_content

def get_center():
    with open("./template/center.html", 'r') as f:
        f_content = f.read()

    mysql_content = "       "
    f_content = f_content.replace("{%content%}", mysql_content)
    return f_content

#     
Env = {
    "/gettime.html": get_time,
    "/index.html":get_index,
    "/center.html": get_center
}

def app(env):
    #   env     web              
    print("          ")
    path_info = env["PATH_INFO"]
    if path_info in Env:
        return "200 ok", [('Server', 'py1.0')], Env[path_info]()
    else:
        #       
        return "404 Not Forund", [('Server','py1.0')], "this is test frame"

自分でフレームワークを簡単に実現することで、pythonサーバやフレームワークをより深く理解することができます.