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

调用一次accept仍多客户端连接?UNIX套接字问题修复

问题分析

你遇到的现象本质是TCP连接队列的工作机制导致的:

  • listen(serverSocket, 1)中的backlog参数限制的是已完成三次握手但未被accept的连接队列长度,而非服务端同时能处理的连接总数。
  • 无延迟场景下:服务端快速调用accept取出第一个连接后,完成队列立刻空出位置,第二个客户端的连接请求能顺利完成三次握手进入队列,因此connect成功;但服务端此时卡在recv调用上,并未处理第二个连接,导致你误以为“仅调用一次accept却有两个连接成功”。
  • 加延迟场景下:服务端在listen后迟迟不调用accept,完成队列被第一个连接占满,第二个客户端的连接请求完成三次握手时,内核因队列无空位直接发送RST包,导致客户端connect失败(errno=61),这符合你预期的“同一时间仅一个连接成功”的结果。
修复方案

要实现“处理第一个连接期间,新客户端无法成功connect”的需求,核心是让服务端在处理连接时暂停接受新的连接请求,最直接的代码层面方案是:在accept第一个连接后关闭监听套接字,处理完当前连接后再重新创建监听套接字。

修改后的服务端代码

#include <iostream>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <chrono>
#include <thread>

#define SOCK_PATH "./server.sock"

int main() {
    while (true) {
        // 每次循环重新创建监听套接字
        int serverSocket = socket(AF_UNIX, SOCK_STREAM, 0);
        if (serverSocket == -1) {
            std::cerr << "Failed to create socket." << std::endl;
            return 1;
        }

        sockaddr_un serverAddress;
        serverAddress.sun_family = AF_UNIX;
        strcpy(serverAddress.sun_path, SOCK_PATH);
        // 先删除旧的套接字文件,避免bind失败
        unlink(SOCK_PATH);

        int bindResult = bind(serverSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress));
        if (bindResult == -1) {
            std::cerr << "Failed to bind socket to address." << std::endl;
            close(serverSocket);
            return 1;
        }

        int listenResult = listen(serverSocket, 1);
        if (listenResult == -1) {
            std::cerr << "Failed to listen for connections." << std::endl;
            close(serverSocket);
            return 1;
        }

        std::cout << "Server is listening for connections..." << std::endl;

        // 接受一个客户端连接
        int clientSocket = accept(serverSocket, nullptr, nullptr);
        if (clientSocket == -1) {
            std::cerr << "Failed to accept client connection." << std::endl;
            close(serverSocket);
            return 1;
        }

        // 关闭监听套接字,拒绝后续连接请求
        close(serverSocket);
        std::cout << "Client connected. No new connections will be accepted until this one closes." << std::endl;

        // 处理客户端连接(recv会阻塞直到客户端发送数据或断开)
        char buffer[1024];
        int bytesRead = recv(clientSocket, buffer, sizeof(buffer), 0);
        if (bytesRead == -1) {
            std::cerr << "Failed to receive data from client." << std::endl;
            close(clientSocket);
            return 1;
        } else if (bytesRead == 0) {
            std::cout << "Client disconnected." << std::endl;
        } else {
            std::cout << "Received data from client: " << buffer << std::endl;
        }

        close(clientSocket);
    }

    return 0;
}

方案说明

  • 每次循环重新创建监听套接字,通过unlink提前删除旧套接字文件,避免绑定失败。
  • 接受第一个连接后立即关闭监听套接字,此时新的客户端连接请求会因目标套接字不存在而失败。
  • 处理完当前客户端连接后,循环会重新创建监听套接字,恢复接受新连接的能力。

内容的提问来源于stack exchange,提问作者saiteja2894

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 20:22:03