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

实例化socket是否属于不良实践?C++ Asio服务端单例套接字无响应求助

问题诊断
  • 构造函数阻塞无法返回:ServerSocket构造函数内包含for(;;)无限循环,调用GetInstance()触发构造时会永远卡在循环中,后续代码完全无法执行,自然无法执行后续的写入逻辑,只有在循环内accept后立刻写数据才能生效。
  • 核心对象生命周期错误:asio::io_context是构造函数内的局部变量,即便构造函数能退出,io_context会被立刻销毁,所有依赖它的socket、acceptor都会直接失效。
  • 成员指针未初始化:循环内的tcp::socket是局部变量,循环结束就会被销毁,类成员的socket指针从未被赋值,返回的是空指针/野指针,后续write操作会直接触发崩溃。
  • 单例设计不符合服务端逻辑:TCP服务端需要支持多客户端连接,每个连接对应独立的socket对象,全局仅保留一个socket的设计根本无法处理多连接场景。
  • 调用逻辑错误:SendUser中定义的ServerSocket* instance未初始化就调用方法,属于野指针访问,存在崩溃风险。
修复方案
  1. 调整核心对象的生命周期:将io_context、acceptor改为类成员变量,保证其生命周期和单例一致。
  2. 拆分监听逻辑:将accept死循环放到独立线程中执行,避免阻塞构造函数返回。
  3. 存储客户端连接:新增线程安全的容器存储所有接入的客户端socket,而非仅保留单个指针。
  4. 修正调用逻辑:直接通过类名调用静态的GetInstance()方法,避免野指针问题。

修复后代码示例

头文件定义

#include <asio.hpp>
#include <iostream>
#include <vector>
#include <mutex>
#include <thread>
#include <memory>

using asio::ip::tcp;

class ServerSocket
{
public:
    ServerSocket(ServerSocket& otherSingleton) = delete;
    void operator=(const ServerSocket& copySingleton) = delete;

    static ServerSocket* GetInstance();
    // 发送数据到最新接入的客户端,可根据需求修改为指定客户端发送
    void SendData(const std::string& data);

private:
    static ServerSocket* instance;
    static std::mutex instanceMutex;

    asio::io_context io_context;
    tcp::acceptor acceptor;
    std::vector<std::unique_ptr<tcp::socket>> connections;
    std::mutex connMutex;
    std::thread acceptThread;

    ServerSocket();
    ~ServerSocket();
    void AcceptLoop();
};

cpp实现

ServerSocket* ServerSocket::instance = nullptr;
std::mutex ServerSocket::instanceMutex;

ServerSocket* ServerSocket::GetInstance()
{
    std::lock_guard<std::mutex> lock(instanceMutex);
    if (instance == nullptr)
    {
        instance = new ServerSocket();
    }
    return instance;
}

ServerSocket::ServerSocket() : acceptor(io_context, tcp::endpoint(tcp::v4(), 13))
{
    std::cout << "Server started" << std::endl;
    // 启动独立线程跑监听逻辑
    acceptThread = std::thread(&ServerSocket::AcceptLoop, this);
}

ServerSocket::~ServerSocket()
{
    io_context.stop();
    if (acceptThread.joinable())
    {
        acceptThread.join();
    }
    std::cout << "Server closed" << std::endl;
}

void ServerSocket::AcceptLoop()
{
    try
    {
        for (;;)
        {
            auto newSocket = std::make_unique<tcp::socket>(io_context);
            acceptor.accept(*newSocket);
            std::lock_guard<std::mutex> lock(connMutex);
            connections.push_back(std::move(newSocket));
        }
    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }
}

void ServerSocket::SendData(const std::string& data)
{
    std::lock_guard<std::mutex> lock(connMutex);
    if (connections.empty())
    {
        std::cerr << "No client connected" << std::endl;
        return;
    }
    // 示例是发给最新接入的客户端,可根据需求修改为遍历所有连接发送
    asio::error_code ignored_error;
    asio::write(*connections.back(), asio::buffer(data), ignored_error);
}

SendUser逻辑修改

void DBUser::SendUser()
{
    try
    {
        ServerSocket::GetInstance()->SendData(m_user);
    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 18:45:03