【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:
把vector
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作业要截止了,那个又得费时间。