单客户端Socket连接下,HTTP服务器是否会收到乱序数据?
TCP Socket数据顺序与HTTP请求解析疑问
背景与实现代码
我正在自行实现一个Python HTTP服务器,目的是快速记录和分析传入的HTTP请求,同时避免依赖需要C绑定的第三方库。以下是已实现的核心代码:
SocketServer实现
import socket import threading import queue import ssl from manipulator.parser import LineBuffer,LoggableHttpRequest class SocketServer: """ Basic Socket Server in python """ def __init__(self,host,port,max_threads,ssl_context:ssl.SSLContext=None): print("Create Server For Http") self.host = host self.port = port self.server_socket = self.initSocket() self.max_threads = max_threads self.request_queue = queue.Queue() self.ssl_context=None if(ssl_context != None): print("Initialise SSL context") self.ssl_context = ssl_context def initSocket(self): return socket.socket(socket.AF_INET, socket.SOCK_STREAM) def __accept(self): self.server_socket.listen(5) while True: try: client_socket, client_address = self.server_socket.accept() if self.ssl_context is not None : print(self.ssl_context) client_socket = self.ssl_context.wrap_socket(client_socket, server_side=True) self.request_queue.put((client_socket, client_address)) except: print("Error Occured") def __handle(self): while True: client_socket, address = self.request_queue.get() print("Address",address) try: # Read HTTP Request # Log Http Request # Manipulate Http Request # Forward or respond buffer = LineBuffer() request = HttpRequest(self.db) buffer.pushData(client_socket.recv(2048)) line = buffer.getLine() if(line is not None): request.parse(line) content = '<html><body>Hello World</body></html>\r\n'.encode() headers = f'HTTP/1.1 200 OK\r\nContent-Length: {len(content)}\r\nContent-Type: text/html\r\n\r\n'.encode() client_socket.sendall(headers + content) finally: client_socket.shutdown(socket.SHUT_RDWR) client_socket.close() self.request_queue.task_done() def __initThreads(self): for _ in range(self.max_threads): threading.Thread(target=self.__handle, daemon=True).start() def start(self): self.server_socket.bind((self.host, self.port)) self.__initThreads() self.__accept()
LineBuffer组件实现
class LineBuffer: def __init__(self): self.buffer = b'' def pushData(self,line): self.buffer += str.encode(line) def getLine(self): if b'\r\n' in self.buffer: line,sep,self.buffer = self.buffer.partition(b'\r\n') return line+sep return None
待实现的HttpRequest与HttpParser组件
class HttpRequest: def __init__(self,db): self.headers={} #ParsedHeaderrs self.body="" #Http Body self.version=None self.method=None self.id=None self.raw="" class HttpParser: def __init__(self,db): self.db = db self.currentRequest=None def parse(line): # do parsing here return
担忧的场景
我担心单个客户端在同一个连接上发送两个HTTP请求时,服务器收到的数据顺序混乱:
请求1
GET / HTTP/1.1\r\n HOST lala1.com \r\n
请求2
POST /file HTTP/1.1\r\n HOST lala2.com \r\n \r\n Qm9QUVM5NDMuLnEvXVN7O2E= fDMpQjcpOlFodClgOGUzYQ== NVgvNipmU1d3YFgtLFUhQiM= MiZwSk0zKno9TkVxNyZFL3s= NEhGJXZ7OGciOE8mYF5JNA== dVlJLzpdKlUjXl4tcEpufQ== XVgiXCdjQyckMjY/Ikt6Rw== alksJlZ+XHFzQSYqaHlHIztt YiRnPjdye0gvanV3ZGxaZkI= MjgwTX0uYHw6M295RS52UDM= YU0yQ2dQLmJUQVpCNS89PWJB Ti10MHJBTjAqUFUlIU0sMyRN
担心收到的乱序数据
GET / HTTP/1.1\r\n POST /file HTTP/1.1\r\n HOST lala1.com \r\n \r\n\r\nQm9QUVM5ND HOST lala2.com \r\n MuLnEvXVN7O2E= fDMpQjcpOlFodClgOGUzYQ== NVgvNipmU1d3YFgtLFUhQiM= MiZwSk0zKno9TkVxNyZFL3s= NEhGJXZ7OGciOE8mYF5JNA== dVlJLzpdKlUjXl4tcEpufQ== XVgiXCdjQyckMjY/Ikt6Rw== alksJlZ+XHFzQSYqaHlHIztt YiRnPjdye0gvanV3ZGxaZkI= MjgwTX0uYHw6M295RS52UDM= YU0yQ2dQLmJUQVpCNS89PWJB Ti10MHJBTjAqUFUlIU0sMyRN \r\n
核心疑问
这种数据顺序混乱的场景是否可能发生?还是TCP Socket会自行保证数据顺序?
回答
TCP是面向字节流的可靠传输协议,它会严格保证接收端读取到的字节顺序和发送端发送的顺序完全一致,你担心的这种乱序场景不可能出现。
TCP在传输时会将数据拆分成TCP段,网络传输中这些段可能会走不同路径,但接收端的TCP协议栈会负责按照发送顺序重新组装这些段,最终通过recv()读取到的字节流是连续且顺序正确的。
不过你的代码存在几个可能导致解析错误的问题,需要注意:
- LineBuffer的pushData方法错误:
str.encode(line)会把传入的bytes先转成字符串再转回bytes,容易引发编码异常,应该直接修改为self.buffer += line。 - 单次recv()无法读取完整请求:HTTP请求可能分多次到达,你需要循环调用
recv()直到根据请求头的Content-Length或分块编码标记判断请求已完整。 - 长连接处理逻辑缺失:HTTP/1.1默认使用长连接,客户端可能在同一个socket上发送多个请求,你当前处理完一次请求就关闭socket的逻辑会断开长连接,需要调整为持续读取直到客户端主动关闭连接或请求结束。
内容的提问来源于stack exchange,提问作者Dimitrios Desyllas
相关产品推荐
相关产品推荐

