通过HTTP协议可以进行通信可以规范化的进行网络间通信。下面技术第一个http服务器小程序。简单的记录第一个试手程序。
1.http通信的基本流程
整个流程对应四层网络架构:应用层、传输层、网络层、链路层。有的部分已经封装,不需要我们再行处理。
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_INETif type == -1:type = SOCK_STREAMif proto == -1:proto = 0_socket.socket.__init__(self, family, type, proto, fileno)self._io_refs = 0self._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 socketrepresenting 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 ProcessHTML_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) # 设置最大连接数20print("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 访问结果