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

基于C++/boost socket的简单客户端/服务端Windows正常Linux失效

基于boost::socket的客户端/服务端在Linux下无响应问题

我实现了一个极简的boost::socket客户端/服务端,需求是服务端持续运行,支持客户端反复连接、发送数据、断开。Windows下运行完全正常:服务端启动后输出对应信息,客户端连接后服务端能正常接收数据、响应断开操作;按下服务端控制台Enter键可干净退出。但在Linux下编译运行同一代码时,客户端输出正常,服务端却完全无响应,请问这是什么原因?


服务端代码

#include <iostream>

#include <boost/asio.hpp>
#include <boost/thread.hpp>

using boost::asio::ip::tcp;

class TheServer
{
public:
    TheServer(int port) : m_port(port)
    {
        m_pIOService = new boost::asio::io_service;

        m_pThread = new boost::thread(boost::bind<void>(&TheServer::run, this));

        listenForNewConnection();
    }
    ~TheServer()
    {
        m_bContinueReading = false;

        m_pIOService->stop();
        m_pThread->join();

        delete m_pThread;
        delete m_pSocket;
        delete m_pAcceptor;
        delete m_pIOService;
    }

    void listenForNewConnection()
    {
        if (m_pSocket)
            delete m_pSocket;
        if (m_pAcceptor)
            delete m_pAcceptor;
        
        // start new acceptor operation
        m_pSocket = new tcp::socket(*m_pIOService);
        m_pAcceptor = new tcp::acceptor(*m_pIOService, tcp::endpoint(tcp::v4(), m_port));

        std::cout << "Starting async_accept" << std::endl;

        m_pAcceptor->async_accept(*m_pSocket,
            boost::bind<void>(&TheServer::readSession, this, boost::asio::placeholders::error));
    }

    void readSession(boost::system::error_code error)
    {
        if (!error)
        {
            std::cout << "Connection established" << std::endl;
            while ( m_bContinueReading )
            {
                static unsigned char buffer[1000];
                boost::system::error_code error;
                size_t length = m_pSocket->read_some(boost::asio::buffer(&buffer, 1000), error);
                if (!error && length != 0)
                {
                    std::cout << "Received " << buffer << std::endl;
                }
                else
                {
                    std::cout << "Received error, connection likely closed by peer" << std::endl;
                    break;
                }
            }
            std::cout << "Connection closed" << std::endl;
            listenForNewConnection();
        }
        else
        {
            std::cout << "Connection error" << std::endl;
        }

        std::cout << "Ending readSession" << std::endl;
    }

    void run()
    {
        while (m_bContinueReading)
            m_pIOService->run_one();
        std::cout << "Exiting run thread" << std::endl;
    }

    bool m_bContinueReading = true;
    boost::asio::io_service* m_pIOService = NULL;
    tcp::socket* m_pSocket = NULL;
    tcp::acceptor* m_pAcceptor = NULL;
    boost::thread* m_pThread = NULL;
    int m_port;
};

int main(int argc, char* argv[])
{
    TheServer* server = new TheServer(1900);

    std::cout << "Press Enter to quit" << std::endl;
    std::string sGot;
    getline(std::cin, sGot);

    delete server;

    return 0;
}

客户端代码

#include <iostream>

#include <boost/asio.hpp>
#include <boost/thread.hpp>

int main(int argc, char* argv[])
{
    std::cout << std::endl;
    
    std::cout << "Starting client" << std::endl;

    using boost::asio::ip::tcp;
    boost::asio::io_service* m_pIOService = NULL;
    tcp::socket* m_pSocket = NULL;

    try
    {
        m_pIOService = new boost::asio::io_service;

        std::stringstream sPort;
        sPort << 1900;

        tcp::resolver resolver(*m_pIOService);
        tcp::resolver::query query(tcp::v4(), "localhost", sPort.str());
        tcp::resolver::iterator iterator = resolver.resolve(query);

        m_pSocket = new tcp::socket(*m_pIOService);
        m_pSocket->connect(*iterator);

        std::cout << "Client conected" << std::endl;

        std::string hello = "Hello World";
        boost::asio::write( *m_pSocket, boost::asio::buffer(hello.data(), hello.size()) );
        boost::this_thread::sleep(boost::posix_time::milliseconds(100));
        hello += "(2)";
        boost::asio::write(*m_pSocket, boost::asio::buffer(hello.data(), hello.size()));

    }
    catch (std::exception& e)
    {
        delete m_pSocket;
        m_pSocket = NULL;
        std::cerr << "Exception: " << e.what() << std::endl;
    }

    return 0;
}

问题原因分析

  1. TCP端口重用限制:
    Linux系统下,当服务端关闭旧的acceptor和socket后,对应端口会进入TIME_WAIT状态,默认不允许立即重新绑定同一端口。而服务端在listenForNewConnection中创建新tcp::acceptor时,未设置reuse_address选项,导致绑定操作失败,async_accept无法正常启动,因此服务端无法响应客户端的连接请求。Windows系统对端口重用的限制更宽松,所以不会触发该问题。

  2. 多线程内存可见性问题:
    成员变量m_bContinueReading是普通bool类型,在多线程环境下(主线程修改、IO线程读取)存在内存可见性问题,Linux下的内存模型可能导致IO线程无法及时感知主线程的修改,进一步加剧无响应的表象。

  3. 标准输出缓冲差异:
    Linux下stdout默认是行缓冲模式,非主线程的输出可能因缓冲未及时刷新,导致信息无法立即显示在控制台,让服务端看起来完全无响应。


修复方案

  1. 添加端口重用选项:
    在创建tcp::acceptor后,设置reuse_address允许端口重用:

    m_pAcceptor = new tcp::acceptor(*m_pIOService, tcp::endpoint(tcp::v4(), m_port));
    m_pAcceptor->set_option(boost::asio::socket_base::reuse_address(true)); // 新增此行
    
  2. 优化线程同步:
    将m_bContinueReading改为原子类型,确保多线程下的内存可见性:

    #include <atomic>
    std::atomic<bool> m_bContinueReading = true;
    
  3. 改进内存管理:
    使用智能指针(如std::unique_ptr)替代裸指针,避免内存泄漏和悬空指针问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 03:41:31