zoukankan      html  css  js  c++  java
  • HTTPserver v3.0 版本项目

    项目介绍

    模拟使用 socket  多线程 / io多路复用 实现一个简单的 httpserver 和 webframe 交互的项目程序 

    期望可以实现简单的 以 http 协议为标准的 和浏览器 / 前端框架的 数据交互

    以及 实现简单的 前端框架模型 

    项目需求分析

    项目分为两部分 httpserver 部分以及 webframe 部分

    HTTPserver 部分

    1. 获取 http 请求

    2. 解析 http 请求

    3. 将请求发送给 WebFrame

    4. 从 WebFrame 接收数据信息

    5. 将数据信息组织为 Response 发送给客户端

    WebFrame 部分

    1. 从 httpserver 获取具体请求

    2. 根据请求进行逻辑或者数据处理 (简单处理, 这里不会过分细致)

    3. 将数据资源发送给 httpserver

    两部分整合后应实现的程度

    1. httpserver 与应用程序分离, 各自独立

    2. 独立开发, 降低互相干扰, 采用各自的配置模式

    3. 在后端应用程序中优化数据的处理模型 (暂时就先不做了)

    高并发需求处理

    1. 多线程

    2. IO 多路复用

    项目实现

    项目结构

     

     项目流程

     

    项目源码

    httpserver 部分

    httpserver.py

    内部实现功能

    1. 作为浏览器的 socket_server 需要创建------>服务器套接字 (配合多线程)

    2. 接收浏览器的 请求进行处理 ------> 处理函数

    3. 作为 webframe 的 socket_client 需要创建------->客户端套接字

    4. 向 webframe 发送请求 -------> 处理函数 

    #!/user/bin/env python3
    # coding=utf8
    """
    AID httpserver v3.0
    """
    
    from socket import *
    import sys
    import json
    from threading import Thread
    
    # 导入配置信息
    from httpserver_config import *
    
    
    # 向 frame 发送请求
    def connect_frame(**kwargs):
        s = socket()
        try:
            s.connect(frame_address)
        except Exception as e:
            print(e)
            return
        # 将请求发送给 frame
        s.send(json.dumps(kwargs).encode())
        data = s.recv(4096).decode()
        return data
    
    
    # 封装 httpserver 基本功能
    class HTTPserver(object):
        def __init__(self, address):
            self.address = address
            self.create_socket()
            self.bind(address)
    
        # 创建套接字
        def create_socket(self):
            self.sockfd = socket()
            self.sockfd.setsockopt(SOL_SOCKET, SO_REUSEADDR, DEBUG)
    
        # 绑定监听地址和端口
        def bind(self, address):
            self.ip = address[0]
            self.port = address[1]
            self.sockfd.bind(address)
    
        #  启动服务
        def serve_forever(self):
            self.sockfd.listen(10)
            print("Listen the port %d ..." % self.port)
            while True:
                try:
                    connfd, addr = self.sockfd.accept()
                    print("Connect from", addr)
                except KeyboardInterrupt:
                    self.sockfd.close()
                    sys.exit("退出 httpserver 服务")
                except Exception as e:
                    print(e)
                    continue
                client = Thread(target=self.handle, args=(connfd,))
                client.setDaemon(True)
                client.start()
    
        # 处理浏览器的 http 请求
        def handle(self, connfd):
            request = connfd.recv(4096)
            # 处理客户端断开
            if not request:
                connfd.close()
                return
            request_lines = request.splitlines()
            # 获取请求行
            request_lines = request_lines[0].decode("utf-8")
            print(request_lines)
            # 这里可以使用正则当然更好, 但是目前来说无大用
            # 获取请求方法, 请求内容
            tmp = request_lines.split(" ")
            method = tmp[0]
            path_info = tmp[1]
    
            data = connect_frame(method=method, path_info=path_info)
    
            self.response(connfd, data)
    
        #  处理返回的数据内容
        def response(self, connfd, data):
    
            # 根据情况组织响应
            if data != "404":
                response_headlers = "HTTP/1.1 200 OK
    "
            else:
                response_headlers = "HTTP/1.1 404 Not Found
    "
    
            response_headlers += '
    '
            response_body = data
            response = response_headlers + response_body
            connfd.send(response.encode())
            connfd.close()
    
    
    httpd = HTTPserver(ADDR)
    httpd.serve_forever()  # 启动服务程序

     httpserver_config.py

    htttpserver 的配置文件相关

    """
    HTTPserver 配置文件, 用户填写基本的必要信息
    """
    
    # HTTPserver
    HOST = "0.0.0.0"
    PORT = 8000
    ADDR = (HOST, PORT)
    
    # debug 设置为 True 表示调试
    DEBUG = True
    
    # 配合 WebFrame 地址
    frame_ip = "127.0.0.1"
    frame_port = 8080
    frame_address = (frame_ip, frame_port)

    webframe 部分

    webframe.py 

    内部实现功能

    1. 作为 httpserver 的服务端处理其请求 ----> 创建 socket_server ( IO多路复用 select 方式 )

    2. 处理请求 ---->  对具体的 url 具体分支处理函数

    #!/user/bin/env python3
    # coding=utf8
    
    """
    模拟网站后端应用处理程序
    httpserver v3.0
    """
    
    from socket import *
    import select
    import json
    
    # 导入配置文件
    from settings import *
    from views import *
    
    
    # 创建应用类, 用于具体处理请求
    class Application(object):
        def __init__(self):
            self.ip = frame_address[0]
            self.port = frame_address[1]
            self.sockfd = socket()
            self.sockfd.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
            self.sockfd.bind(frame_address)
    
        def start(self):
            self.sockfd.listen(5)
            print("Listen the port %d" % self.port)
            rlist = [self.sockfd]
            wlist = []
            xlist = []
            while True:
                rs, ws, xs = select.select(rlist, wlist, xlist)
                # 循环检查是否就绪
                for r in rs:
                    #  判断加入 关注列表
                    if r is self.sockfd:
                        connfd, addr = r.accept()
                        rlist.append(connfd)
                    else:
                        # 接受 httpserver 的请求
                        request = r.recv(2048).decode()
                        if not request:
                            rlist.remove(r)
                            continue
                        self.handle(r, request)
    
        # 处理请求
        def handle(self, connfd, request):
            request = json.loads(request)
            method = request["method"]
            path_info = request["path_info"]
            print(path_info)
            if method == "GET":
                if path_info == "/" or path_info[-5:] == ".html":
                    data = self.get_html(path_info)
                else:
                    data = self.get_data(path_info)
            elif method == "POST":
                pass
            # 得到网页内容就发送 未得到就发送404
            if data:
                connfd.send(data.encode())
            else:
                connfd.send(b"404")
    
        # 处理网页
        def get_html(self, path_info):
            if path_info == "/":
                get_file = STATIC_DIR + "/index.html"
            else:
                get_file = STATIC_DIR + path_info
            try:
                fd = open(get_file, encoding="utf8")
                data = fd.read()
            except IOError:
                return
            return data
    
        # 处理数据
        def get_data(self, path_info):
            for url, func in urls:
                if path_info == url:
                    return func()
            return "404"
    
    
    app = Application()
    app.start()  # 启动后端框架服务

    settings.py

    框架的配置文件

    以及 自定义的函数对应方法的映射配置 类似于 Django 的路由系统

    """
    Frame 程序配置文件
    """
    from views import *
    
    
    # 配置框架地址
    frame_ip = "0.0.0.0"
    frame_port = 8080
    frame_address = (frame_ip, frame_port)
    
    # 静态网页位置
    STATIC_DIR = "./static"
    
    #
    urls = [
        ("/time", show_time),
        ("/hello", say_hello)
    ]

    views.py

    自定义的返回视图函数, 类似于 Django 的 视图系统

    import time
    
    
    def show_time():
        return time.ctime()
    
    
    def say_hello():
        return "Hello world"
  • 相关阅读:
    Silverlight与WPF开发人员入门应该知道的十件事
    Silverlight4.0教程之使用鼠标右键事件和滚轮事件
    Silverlight实用窍门系列:4.Silverlight 4.0添加鼠标右键菜单和Silverlight全屏模式的进入退出。【附带源码实例】
    将moss 2007的模板文件导入到moss 2010
    Silverlight4.0教程之打印报表和图形
    .NET MessageBox 网页弹出消息框
    使用sharepoint自带的文本编辑器1
    C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):目录
    推荐一个非常好的在线免费的 Photoshop
    Silverlight游戏设计(Game Design):目录
  • 原文地址:https://www.cnblogs.com/shijieli/p/10516501.html
Copyright © 2011-2022 走看看