Python学习笔记-基于socket基础的http服务端程序

通过HTTP协议可以进行通信可以规范化的进行网络间通信。下面技术第一个http服务器小程序。简单的记录第一个试手程序。

1.http通信的基本流程

Python学习笔记-基于socket基础的http服务端程序_第1张图片

整个流程对应四层网络架构:应用层、传输层、网络层、链路层。有的部分已经封装,不需要我们再行处理。

2.服务器程序设置

2.1 创建一个socket对象

self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

第一个参数是指定IP协议,第二个参数用于指定通信方式。

官方构造函数解释如下:

    def __init__(self, family=-1, type=-1, proto=-1, fileno=None):
        # For user code address family and type values are IntEnum members, but
        # for the underlying _socket.socket they're just integers. The
        # constructor of _socket.socket converts the given argument to an
        # integer automatically.
        if fileno is None:
            if family == -1:
                family = AF_INET
            if type == -1:
                type = SOCK_STREAM
            if proto == -1:
                proto = 0
        _socket.socket.__init__(self, family, type, proto, fileno)
        self._io_refs = 0
        self._closed = False

基本参数信息如下:

AF_INET = AddressFamily.AF_INET

IPv4地址

AF_INET6 = AddressFamily.AF_INET6

IPv6地址

SOCK_STREAM = SocketKind.SOCK_STREAM

基于TCP传输

SOCK_DGRAM = SocketKind.SOCK_DGRAM

基于UDP传输

2.2 绑定IP和端口

def bind(self, __address: _Address) -> None: ...

_Address: TypeAlias = tuple[Any, ...] | str | ReadableBuffer

指定一个地址进行绑定。

通过元组的形式指定IP地址和端口号:

self.server_socket.bind(("", port))

注意,需要使用元组型号的数据,第一个参数是IP地址,第二个参数是端口号,使用空字符串”“默认为本地IP地址:127.0.0.1。

2.3 启动监听

def listen(self, __backlog: int = ...) -> None: ...

设置监听数量,即允许同时连接的最大客户端数量。

2.4 接收请求

    def accept(self):
        """accept() -> (socket object, address info)

        Wait for an incoming connection.  Return a new socket
        representing the connection, and the address of the client.
        For IP sockets, the address info is a pair (hostaddr, port).
        """
        fd, addr = self._accept()
        sock = socket(self.family, self.type, self.proto, fileno=fd)
        # Issue #7995: if no default timeout is set and the listening
        # socket had a (non-zero) timeout, force the new socket in blocking
        # mode to override platform-specific socket flags inheritance.
        if getdefaulttimeout() is None and self.gettimeout():
            sock.setblocking(True)
        return sock, addr

通过accept函数返回请求对象,返回两个参数,一个是请求的socket,一个是请求的地址信息。

client_socket, client_address = self.server_socket.accept()

2.5 处理请求

处理请求就相当于字符串处理,解析报文,进行对应处理。

2.6 应答

def send(self, __data: ReadableBuffer, __flags: int = ...) -> int: ...

通过send函数将bytes数据返回给客户端。

client_socket.send(bytes(response, "utf-8"))

2.7 关闭socket

client_socket.close()

关闭客户端的socket。

注意:此处关闭的是获取到的客户端socket,不是服务器的socket。

3. 示例代码

3.1 服务端代码

# _*_ coding:utf-8 _*_

import socket
import re
import os
from multiprocessing import Process

HTML_ROOT_DIR = "./zero.staticserver/views"


class HTTPServer(object):
    """HTTP server"""

    def __init__(self) -> None:
        """init"""

        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        """初始化socket,IPV4,TCP协议"""

    def bind(self, port):
        """Binding port"""

        self.server_socket.bind(("", port))

    def start(self):
        """Start server"""

        self.server_socket.listen(20)   # 设置最大连接数20
        print("Server started.Waitting to connect...")

        while True:

            # 接收的客户端连接信息
            client_socket, client_address = self.server_socket.accept()
            print("Client Connected. IP:{0},Port:{1}",
                  client_address[0], client_address[1])
            process_client = Process(
                target=self.handle_client, args=(client_socket,))
            process_client.start()
            client_socket.close()

    def handle_client(self, client_socket: socket.socket):
        """handle of client"""

        request_data = client_socket.recv(1024)
        print("Request Data:", request_data)
        print("********逐行输出请求数据*********")

        request_lines = request_data.splitlines()
        for line in request_lines:
            print(line)

        print("********解析报文*********")
        request_start_line = request_lines[0]
        str_request_start_line = request_start_line.decode("utf-8")
        print(str_request_start_line)
        filename = re.match(r"\w+ +(/[^ ]*) ", str_request_start_line).group(1)
        print("File Name : {0}".format(filename))

        if filename == "/":
            filename = "index.html"

        print("root path : {0}".format(os.getcwd()))
        try:
            filepath = f"{HTML_ROOT_DIR}/{filename}"
            file = open(filepath, "rb")
        except IOError:
            # 返回异常
            response_start_line = "HTTP/1.1 404 Not Found"
            response_headers = "Server:First server"
            response_body = "The file is not found."
        else:
            # Read file data.
            filedata = file.read()
            file.close()

            response_start_line = "HTTP/1.1 200 OK"
            response_headers = "Server:First server"
            response_body = filedata.decode("utf-8")

        print("\r\n")
        response = f"{response_start_line}\r\n{response_headers}\r\n\r\n{response_body}"
        print("Response:\r\n{0}".format(response))
        client_socket.send(bytes(response, "utf-8"))
        # Close socket.
        client_socket.close()

3.2 访问结果

Python学习笔记-基于socket基础的http服务端程序_第2张图片

 Python学习笔记-基于socket基础的http服务端程序_第3张图片

 Python学习笔记-基于socket基础的http服务端程序_第4张图片

 

你可能感兴趣的:(Python,学习,笔记)