【work记录:c++web聊天服务器】修复boost服务器的ConnectionMgr的一些细节bug

日期:2025.4.16(凌晨)

个人总结:

经过不懈的努力,把muduo服务器和boost服务器之间的通信换成了前缀长度的形式。

然后是漫长的找bug环节。

首先是如果只是把一个int类型强制转换成char*,而没有声明长度的话,那么就是1,而不是4.

std::string msg((char*)&len);
std::string msg((char*)&len,4);

就像这样,阿巴阿巴新手错误接着犯。

还有一些关于ConnectionMgr的内容:

ConnectionMgr::ConnectionMgr() : _muduo_socket(_io_context), _work_guard(boost::asio::make_work_guard(_io_context))
{
    _io_thread = std::thread([this]()
                             { _io_context.run(); });

    // _io_context.run();

    std::string _ip = "127.0.0.1";
    int _port = 5005;
    ConnectToMuduo(_ip, _port);
}

ConnectionMgr::~ConnectionMgr()
{
    _io_context.stop();
    if (_io_thread.joinable())
    {
        _io_thread.join();
    }
}

_io_context.run();是阻塞当前线程的操作,所以我们需要开一个线程来run。

然后询问ds老师后添加了:_work_guard(boost::asio::make_work_guard(_io_context))

这里我们大概的谈一谈关于io_context,make_work_guard和socket之间的关系:

io_context,make_work_guard和socket

首先是在boost.asio中,这个io_context其实就像是一个事件循环,我们所有调用的异步的函数都会被放到这个io_context里去处理,然后我们调用io_context.run来启动事件循环,就会开始处理我们的异步操作,所以这一步是阻塞的,我们需要拿一个线程出来专门处理这个。

但是这个家伙有一个问题是,如果没有异步操作或者异步操作全部完成了,那么他就会自动退出。所以如果我们想要让他继续保持住,将来有异步操作就交给他,就需要有一个机制来保持io_context是活动的状态,这个时候work_guard就出来了。

为什么需要work_guard

executor_work_guard会保持io_context的“工作计数”(work count)为非零状态。也就是说只要存在活动的work_guard对象,io_context就不会因为所有异步操作完成而停止。换句话说,io_context::run()会一直运行,除非我们显式调用io_context::stop(),或者所有的work_guard都被销毁为止。

socket与io_context的关系

boost::asio::ip::tcp::socket在构造时必须传入一个io_context的引用,这样这个socket的所有异步操作都会被提交到该io_context的事件循环中进行处理。

例如:当调用async_connect时,异步操作会被提交到与该socket关联的io_context,并由io_context在其事件循环中调度处理。当连接完成时,相应的回调函数会被调用。

other:

把vectorrecv_buf改成了正常的char数组,

void ConnectionMgr::RecvFromMuduo()
{
    // 计算还需要读取的字节数
    const size_t bytes_needed = (expect_recv_len == 0) ? 4 : expect_recv_len;
    const size_t has_read = (bytes_needed == 4) ? 0 : 4;
    // 异步读取
    boost::asio::async_read(
        _muduo_socket,
        boost::asio::buffer(recv_buf + has_read, bytes_needed),

之前没有has_read,他的地方之前写的是recv_buf.size(),但是显然是有问题的,毕竟会为了添加内容而resize,但是resize会改变它的容量大小,size会改变,那么第二次异步读取的时候就会越界,然后报错。

改成了char数组,然后改改小细节就OK了。

SendToMuduo函数

void ConnectionMgr::SendToMuduo(std::shared_ptr<Connection> conptr, std::string msg)
{
    json js = json::parse(msg);

    js["uid"] = conptr->getUid();

    std::string send_msg = js.dump();

    int send_len = send_msg.size();
    std::string header_msg((char *)&send_len, 4);
    header_msg += send_msg;
    boost::asio::async_write(
        _muduo_socket,
        boost::asio::buffer(header_msg),
        [](boost::system::error_code ec, size_t bytes_write)
        {
            if (ec)
            {
                // 处理发送失败(例如重试或记录日志)
                std::cout << "SendToMsg 发送失败" << std::endl;
            }
        });
}

这里多了个参数,Connection的指针。

这里阐述一下:我们要把每一次客户端向boost发送的json数据在我们的ConnectonMgr里多加上一个他的uid,然后再转发给muduo,之后muduo收到了uid会把uid上传到他的map里,然后muduo往boost发送数据的时候会在map里查一遍发送对象的uid,然后发回来,boost就可以根据uid来发送数据给正确的对象。

然后差的内容就是把muduo服务器的map改掉,然后发送数据的时候带上uid。

另外还有一点是,关于这个服务器的后续。

现在我们muduo连接的对象只有boost服务器,也就是说客户端可以连到很多的boost服务器(待定?),而muduo服务器接下来我应该并不打算做成集群的形式,毕竟也不是很契合我们的服务器的设置。boost服务器应该会有几台,然后他们之间会做一些之前集群服务器的一些事情,例如如果不在一台boost服务器,但是发送对象目前在线的情况,应该是交由boost服务器去处理,这里应该会用上之前的nginx负载均衡和redis。然后muduo之后应该是朝着分布式模块化去做。

这是目前构思的大概的后续,完全不保证之后会是什么样阿巴阿巴。

现在时间:2025年4月16日04:56:33。扛不住了,下午还有训练赛,还有节早八要去上。明天还是后天有个java作业要截止了,那个又得费时间。

posted @ 2025-04-16 04:58  AdviseDY  阅读(13)  评论(0)    收藏  举报