如何解决curl中‘connection reset by peer’错误并优雅关闭Socket?
问题:HTTP服务器curl请求出现Connection reset by peer错误,如何优雅关闭Socket?
我开发了一个基础HTTP服务器(后续将用于底层HTTP分析与操作),服务器代码如下:
import socket import threading import queue import time class SocketServer: """ Basic Socket Server in python """ def __init__(self,host,port,max_theads): self.host = host self.port = port self.server_socket = self.__initSocket() self.max_theands = max_theads self.request_queue = queue.Queue() def __initSocket(self): return socket.socket(socket.AF_INET, socket.SOCK_STREAM) def __accept(self): self.server_socket.listen(5) while True: client_socket, client_address = self.server_socket.accept() self.request_queue.put((client_socket, client_address)) def __handle(self): while True: # Dequeue a request and process it client_socket, address = self.request_queue.get() # Read HTTP Request # Log Http Request # Manipulate Http Request # Forward or respond client_socket.sendall(b"""HTTP/1.1 200 OK Content-Type: text/html <html><body>Hello World</body></html> """); ; time.sleep(1) client_socket.close() self.request_queue.task_done() def __initThreads(self): for _ in range(self.max_theands): threading.Thread(target=self.__handle, daemon=True).start() def start(self): self.server_socket.bind((self.host, self.port)) self.__initThreads() self.__accept()
通过独立进程启动服务器的代码:
#!/usr/bin/env python3 """ 1. Read settings 2. Bootstrap Manupilator 3. Bootstrap Control Panel """ import multiprocessing from manipulator.http_socket_server import SocketServer if __name__ == "__main__": # @todo read settings file host = "0.0.0.0" port = 80 max_threads = 5 server = SocketServer(host, port, max_threads) server_process = multiprocessing.Process(target=server.start) server_process.start() # Add other main application code here if needed server_process.join()
使用curl请求时收到如下错误:
curl 10.0.0.2 <html><body>Hello World</body></html> curl: (56) Recv failure: Connection reset by peer
即使在__handle函数中加入time.sleep(1)延迟,问题仍然存在。请问如何优雅关闭Socket?
问题原因
出现这个错误的核心是没有遵循HTTP协议的完整交互逻辑:
- 服务器未读取客户端发送的HTTP请求就直接关闭连接,TCP层会触发RST包,导致curl认为连接异常中断
- HTTP/1.1默认启用Keep-Alive持久连接,直接关闭socket会破坏协议约定,客户端仍在等待连接保持或后续数据
解决方案
1. 修改后的__handle函数代码
def __handle(self): while True: client_socket, address = self.request_queue.get() try: # 读取客户端请求数据(循环读取直到缓冲区为空) request_data = client_socket.recv(4096) while request_data: request_data = client_socket.recv(4096) # 发送响应,添加Connection: close头告知客户端关闭连接 client_socket.sendall(b"""HTTP/1.1 200 OK Content-Type: text/html Connection: close <html><body>Hello World</body></html> """) # 先关闭写通道,通知客户端不再发送数据 client_socket.shutdown(socket.SHUT_WR) # 短暂等待客户端读取完响应 time.sleep(0.1) except Exception as e: print(f"处理请求出错: {e}") finally: # 最终关闭socket client_socket.close() self.request_queue.task_done()
2. 关键优化点
- 读取完整请求数据:避免TCP缓冲区残留数据导致连接异常
- 添加
Connection: close响应头:明确告知客户端本次交互后关闭连接,符合HTTP协议约定 - 使用
shutdown(socket.SHUT_WR):先关闭socket的写通道,让客户端知道服务器已发送完所有数据,客户端会主动关闭连接,避免RST包产生 - 异常捕获:处理socket交互中的异常,防止线程崩溃
3. 可选:支持Keep-Alive持久连接
如果需要支持持久连接,可以解析请求头中的Connection字段,决定是否保持连接:
def __handle(self): while True: client_socket, address = self.request_queue.get() keep_alive = False try: # 读取请求数据并解析Connection字段 request_data = client_socket.recv(4096) if b"Connection: keep-alive" in request_data: keep_alive = True # 循环读取完整请求 while request_data: request_data = client_socket.recv(4096) # 构造响应头 response_header = b"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n" if keep_alive: response_header += b"Connection: keep-alive\r\nKeep-Alive: timeout=5\r\n" else: response_header += b"Connection: close\r\n" response = response_header + b"\r\n<html><body>Hello World</body></html>\r\n" client_socket.sendall(response) if not keep_alive: client_socket.shutdown(socket.SHUT_WR) time.sleep(0.1) client_socket.close() except Exception as e: print(f"处理请求出错: {e}") client_socket.close() finally: if not keep_alive: self.request_queue.task_done()
内容的提问来源于stack exchange,提问作者Dimitrios Desyllas
相关产品推荐
相关产品推荐

