You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决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协议的完整交互逻辑:

  1. 服务器未读取客户端发送的HTTP请求就直接关闭连接,TCP层会触发RST包,导致curl认为连接异常中断
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 14:23:10