自学内容网 自学内容网

Python使用socket实现简易的http服务

在接触的一些项目中,有时为了方便可视化一些服务状态(请求数很少),那么很容易想到使用http服务来实现。但开源的web后端框架,例如flask,fastapi,django等略显沉重,且使用这些框架会有各种各样的限制,为了更加灵活的使用,可以自己通过Python自带的socket库来实现,下面是我简单实现的代码,贴在这里方便后续使用。

客户端代码:

import os
import time
import json
import socket
import datetime
import traceback
from urllib import parse


ENCODING = "utf-8"


class CustomRouter:
    def __init__(self):
        self.router_dict = {}

    def register(self, url: str, method: str):
        if method not in ["GET", "POST"]:
            raise ValueError(f"method only support GET or POST, got {method}")

        key = f"{url}:{method}"
        if key in self.router_dict:
            raise ValueError(f"url:{url} method:{method} already registed")

        def _register(func):
            self.router_dict[key] = func
            return func

        return _register

    def has_register(self, url: str, method: str):
        key = f"{url}:{method}"
        return key in self.router_dict

    def request(self, url: str, method: str):
        key = f"{url}:{method}"
        func = self.router_dict[key]

        return func()


router = CustomRouter()


@router.register(url="/", method="GET")
def task():
    return "Hello World!!!"


@router.register(url="/get_project_info", method="GET")
def get_project_info():
    info = {"pwd": os.path.abspath(os.curdir),
            "encoding": ENCODING,
            "time": datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
    return json.dumps(info)


class CustomServer:
    def __init__(self, port: int = 5055, backlog: int = 2):
        self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.server.bind(("", port))
        self.server.listen(backlog)
        self.buff_size = 1024
        self.encoding = ENCODING
        self.router = router
        self.timeout = 1.0

    def parse_message(self, message: str):
        method, url_params, message = message.split(" ", maxsplit=2)
        res = parse.urlparse(url_params)
        url = res.path
        params = dict([i for i in parse.parse_qsl(res.query)])
        version, message = message.split("\r\n", maxsplit=1)
        return method, url, params, version

    def run(self):
        while True:
            conn, addr = self.server.accept()
            # conn.settimeout(self.timeout)
            with conn:
                try:
                    message = conn.recv(self.buff_size).decode(self.encoding)
                    t0 = time.perf_counter()
                    method, url, params, version = self.parse_message(message)

                    if not self.router.has_register(url, method):
                        conn.send("HTTP/1.1 501 Not Implemented\r\n\r\n".encode(self.encoding))
                        print(f"[{method}][501]client addr: {addr} request: {url}, time: {time.perf_counter() - t0:.5f}")
                        continue

                    res = self.router.request(url, method)
                    conn.send("HTTP/1.1 200 OK\r\n\r\n".encode(self.encoding))
                    conn.send(res.encode(self.encoding))
                    print(f"[{method}][200]client addr: {addr} request: {url}, time: {time.perf_counter() - t0:.5f}")
                except (BrokenPipeError, TimeoutError):
                    print(traceback.format_exc())
                except:
                    print(traceback.format_exc())
                    conn.send("HTTP/1.1 500 Inner Error\r\n\r\n".encode(self.encoding))
                    print(f"[{method}][500]client addr: {addr} request: {url}, time: {time.perf_counter() - t0:.5f}")


if __name__ == '__main__':
    s = CustomServer()
    s.run()

客户端代码:

import requests


def main():
    for _ in range(50):
        res = requests.get("http://127.0.0.1:5055")
        print(res.status_code, res.text)

        res = requests.get("http://127.0.0.1:5055/get_project_info")
        print(res.status_code, res.json())


if __name__ == '__main__':
    main()

客户端请求时,服务端终端输出:

[GET][200]client addr: ('127.0.0.1', 38054) request: /, time: 0.00002
[GET][200]client addr: ('127.0.0.1', 38058) request: /get_project_info, time: 0.00004
[GET][200]client addr: ('127.0.0.1', 38060) request: /, time: 0.00002
[GET][200]client addr: ('127.0.0.1', 38070) request: /get_project_info, time: 0.00004
[GET][200]client addr: ('127.0.0.1', 38080) request: /, time: 0.00002
[GET][200]client addr: ('127.0.0.1', 38096) request: /get_project_info, time: 0.00004
[GET][200]client addr: ('127.0.0.1', 38098) request: /, time: 0.00002
[GET][200]client addr: ('127.0.0.1', 38114) request: /get_project_info, time: 0.00009
[GET][200]client addr: ('127.0.0.1', 38120) request: /, time: 0.00003
[GET][200]client addr: ('127.0.0.1', 38122) request: /get_project_info, time: 0.00006
[GET][200]client addr: ('127.0.0.1', 38136) request: /, time: 0.00003
[GET][200]client addr: ('127.0.0.1', 38146) request: /get_project_info, time: 0.00006
[GET][200]client addr: ('127.0.0.1', 38160) request: /, time: 0.00003
[GET][200]client addr: ('127.0.0.1', 38172) request: /get_project_info, time: 0.00005
[GET][200]client addr: ('127.0.0.1', 38178) request: /, time: 0.00002
[GET][200]client addr: ('127.0.0.1', 38182) request: /get_project_info, time: 0.00005

客户端终端输出:

200 Hello World!!!
200 {'pwd': '/home/wz/my_projects/others/socket_t', 'encoding': 'utf-8', 'time': '2025-01-14 00:20:01'}
200 Hello World!!!
200 {'pwd': '/home/wz/my_projects/others/socket_t', 'encoding': 'utf-8', 'time': '2025-01-14 00:20:01'}
200 Hello World!!!
200 {'pwd': '/home/wz/my_projects/others/socket_t', 'encoding': 'utf-8', 'time': '2025-01-14 00:20:01'}
200 Hello World!!!
200 {'pwd': '/home/wz/my_projects/others/socket_t', 'encoding': 'utf-8', 'time': '2025-01-14 00:20:01'}
200 Hello World!!!
200 {'pwd': '/home/wz/my_projects/others/socket_t', 'encoding': 'utf-8', 'time': '2025-01-14 00:20:01'}
200 Hello World!!!
200 {'pwd': '/home/wz/my_projects/others/socket_t', 'encoding': 'utf-8', 'time': '2025-01-14 00:20:01'}
200 Hello World!!!
200 {'pwd': '/home/wz/my_projects/others/socket_t', 'encoding': 'utf-8', 'time': '2025-01-14 00:20:01'}
200 Hello World!!!
200 {'pwd': '/home/wz/my_projects/others/socket_t', 'encoding': 'utf-8', 'time': '2025-01-14 00:20:01'}

原文地址:https://blog.csdn.net/qq_37541097/article/details/145126993

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!