这一章节我们将实现 TCP 协议的套接字服务的编程,为后续应用层 HTTP 协议 做准备。
技术路线
画图是真的烂,我也是第一次用这个插件,见谅,2333~~~
graph TB
subgraph 自定义
SimpleHTTPServer---SimpleHTTPRequestHandler
SimpleHTTPServer---Client
end
subgraph HTTP
BaseHTTPSercer---BaseHTTPRequsetHandler
BaseHTTPSercer ==> SimpleHTTPServer
BaseHTTPRequsetHandler ==> SimpleHTTPRequestHandler
end
subgraph TCP
TCPServer---StreamRequsetHandler
TCPServer ==> BaseHTTPSercer
StreamRequsetHandler ==> BaseHTTPRequsetHandler
end
在这里说明一下
- TCP 端
- TCPServer :接收客户端的 TCP 连接
- StreamRequsetHandler :封装字节流网络请求处理功能
- HTTP端
- BaseHTTPSercer :基础 HTTP 服务器
- BaseHTTPRequsetHandler :封装 HTTP 请求处理的基础功能
- 自定义
- SimpleHTTPRequestHandler :实现自定义的 HTTP 请求(GET、POST)处理逻辑
图片说明图
本节目录
- http
- handler
- __init__.py
- base_handler.py
- server
- test
本章完成的内容
技术路线图
graph TB
subgraph TCP
TCPServer---StreamRequsetHandler
end
- TCP 端
- TCPServer :接收客户端的 TCP 连接
- StreamRequsetHandler :封装字节流网络请求处理功能
目录结构
graph LR
目录:socket-->socket_server.py
目录:handler-->base_handler.py
- socket 是处理 TCPServer
- handler 是处理 StreamRequsetHandler
涉及的技术
graph LR
TCPServer-->StreamRequsetHandler
StreamRequsetHandler-->多线程TCPServer
- TCPServer
- StreamRequsetHandler
- 多线程TCPServer
TCPServer
后面那些都是方法
graph LR
TCPServer
TCPServer-->启动
启动-->serve_forever
TCPServer-->处理请求
处理请求-->get_request
处理请求-->process_request
处理请求-->close_request
TCPServer-->正常关闭
正常关闭-->shutdown
TCPServer-->a(处理对象:服务端地址-处理器-套接字)
socket_server.py
graph LR
目录:socket-->socket_server.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
|
import socket import threading
class TCPServer:
def __init__(self, server_address, handler_class): self.server_address = server_address self.HandlerClass = handler_class self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.is_shutdown = False
def serve_forever(self): self.socket.bind(self.server_address) self.socket.listen(10) while not self.is_shutdown: request, client_address = self.get_request() try: self.process_request(request, client_address) except Exception as e: print(e)
def get_request(self): return self.socket.accept()
def process_request(self, request, client_address): handler = self.HandlerClass(self, request, client_address) handler.handle() self.close_request(request)
def close_request(self, request): request.shutdown(socket.SHUT_WR) request.close()
def shutdown(self): self.is_shutdown = True
|
StreamRequsetHandler
- BaseRequestHandler
- StreamRequsetHandler
graph LR
BaseRequestHandler
BaseRequestHandler==>StreamRequsetHandler
StreamRequsetHandler
StreamRequsetHandler-->编码/解码
编码/解码-->encode/decode
StreamRequsetHandler-->读/写消息
读/写消息-->read/readline
读/写消息-->write_content
读/写消息-->send
base_handler.py
graph LR
目录:handler-->base_handler.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
|
class BaseRequestHandler: def __init__(self, server, request, client_address): self.server = server self.request = request self.client_address = client_address
def handle(self): pass
class StreamRequestHandler(BaseRequestHandler):
def __init__(self, server, request, client_address): BaseRequestHandler.__init__(self, server, request, client_address)
self.rfile = self.request.makefile('rb') self.wfile = self.request.makefile('wb') self.wbuf = []
def encode(self, msg): if not isinstance(msg, bytes): msg = bytes(msg, encoding='utf-8') return msg
def decode(self, msg): if isinstance(msg, bytes): msg = msg.decode() return msg
def read(self, length): msg = self.rfile.read(length) return self.decode(msg)
def readline(self, length=65536): msg = self.rfile.readline(length).strip() return self.decode(msg)
def write_content(self, msg): msg = self.encode(msg) self.wbuf.append(msg)
def send(self): for line in self.wbuf: self.wfile.write(line) self.wfile.flush() self.wbuf = []
def close(self): self.wfile.close() self.rfile.close()
|
编写测试用例
test.py
graph LR
目录:test-->test.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
|
import time import socket import threading
from server.socket_server import TCPServer from handler.base_handler import StreamRequestHandler
from server.base_http_server import BaseHTTPServer from handler.base_http_handler import BaseHTTPRequestHandler
class TestBaseRequestHandler(StreamRequestHandler):
def handle(self): msg = self.readline() print('Server recv msg: ' + msg) time.sleep(1) self.write_content(msg) self.send() pass
class SocketServerTest: def run_server(self): tcp_server = TCPServer(('127.0.0.1', 8888), TestBaseRequestHandler) tcp_server.serve_forever()
def client_connect(self): client = socket.socket() client.connect(('127.0.0.1', 8888)) client.send(b'Hello TCPServer\r\n') msg = client.recv(1024) print('Client recv msg: ' + msg.decode())
def gen_clients(self, num): clients = [] for i in range(num): client_thread = threading.Thread(target=self.client_connect) clients.append(client_thread) return clients
def run(self): server_thread = threading.Thread(target=self.run_server) server_thread.start()
time.sleep(5)
clients = self.gen_clients(10) for client in clients: client.start()
server_thread.join() for client in clients: client.join()
if __name__ == '__main__': SocketServerTest().run()
|
上面就完成了简单的例子,但是,目前完成的服务器还非常初级,甚至,是单线程工作,下一步,我们将代码改编成多线程。
其实只需要修改
将里面的处理函数,变成多线程处理,其全部代码如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
|
import socket import threading
class TCPServer:
def __init__(self, server_address, handler_class): self.server_address = server_address self.HandlerClass = handler_class self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.is_shutdown = False
def serve_forever(self): self.socket.bind(self.server_address) self.socket.listen(10) while not self.is_shutdown: request, client_address = self.get_request() try: self.process_request_multithread(request, client_address) except Exception as e: print(e)
def get_request(self): return self.socket.accept()
def process_request(self, request, client_address): handler = self.HandlerClass(self, request, client_address) handler.handle() self.close_request(request)
def process_request_multithread(self, request, client_address): t = threading.Thread(target=self.process_request, args=(request, client_address)) t.start()
def close_request(self, request): request.shutdown(socket.SHUT_WR) request.close()
def shutdown(self): self.is_shutdown = True
|