【问题标题】:Segmentation fault with boost::asio, asynchronous udp-server with deadline_timerboost::asio 的分段错误,带有deadline_timer 的异步udp-server
【发布时间】:2014-03-21 09:21:18
【问题描述】:

我在使用 boost::asio 库的服务器程序时遇到问题。

Server 类与 boost asio 教程"asynchronous udp-server"中介绍的非常相似

该类有一个公共方法(“sendMessageTo”),由消息处理器对象调用,如果该方法由deadline_timer线程调用,则会发生分段错误。它发生在 new std::string(msg, len) 的调用中,这让我很困惑。 msg 包含它应该包含的内容,还有 len。

void Server::sendMessageTo(const char* msg, size_t len, udp::endpoint to)
{
    boost::shared_ptr<std::string> message( new std::string (msg,len) );
    socket.async_send_to(boost::asio::buffer(*message), to,
                         boost::bind(&Server::handleSend, this, message,
                                     boost::asio::placeholders::error,
                                     boost::asio::placeholders::bytes_transferred));
}

当第一次尝试调用方法“sendMessageTo”时,一切正常:稍后在同一线程中调用它,该线程由服务器类的“handleReceive”方法打开。

我的消息处理器对象是某种状态机,它保持远程端点,并且在某些状态下定期希望将一些 udp 消息发送回端点。因此使用了 asio::deadline_timer。 截止时间计时器是使用相同的 io_service 创建的,udp 服务器在其上运行。 当定时器第一次被撤销时,message_processor 对象内的 state_handling 方法调用“sendMessageTo”方法,发生分段错误。 “sendMessageTo”的所有参数都是有效的,并且包含预期的值。

我的消息处理器类的构造函数头(称为事务)

Transaction::Transaction(ClientReference *cli, ServerReference *serv)
    : timer(*(serv->getIOService()), boost::posix_time::milliseconds(TRANSACTION_THREAD_SLEEP_MILLISEC)),
      clientEndpoint(serv->getEndpoint())

timer 是 asio::deadline_timer 对象,clientEndpoint 是 udp::endpoint

服务器响应在 Transaction::runThread() 方法中发送

server->sendMessageTo(&encryptedMsgBuf[0], size, clientEndpoint);

encryptedMsgBuf 是一个 char 数组缓冲区,用于存储加密的消息,它是 Transaction - object 的一部分。

在方法 Transaction::runThread() 结束时,deadline_timer 被调用到方法 runThread() 上以重新激活它,直到达到最终状态:

if (state != done && state != expired) 
    timer.async_wait(boost::bind(&Transaction::runThread, this));

谢谢你。

【问题讨论】:

  • Server::handleSend() 长什么样子?
  • 也许您应该显示更多代码。想到一个 SSCCE
  • @Stefan Server::handleSend() 只是一个空的回调处理程序。 @sehe,我正在研究 SSCCE,但同时我发现可能是主要问题。更新问题,如有必要,SSCCE 可能会跟进。

标签: c++ boost udp boost-asio


【解决方案1】:

我不能 100% 确定这一点,因为我无法从您发布的内容中本地重现您的错误,但我强烈怀疑您的问题是由于消息字符串变量的范围限定造成的。我在过去遇到过boost::shared_ptr 的一些问题,其中shared_ptr 的破坏时间比预期的要早。如果是这种情况,那么shared_ptr message 可能会在对Server::sendMessageTo() 的调用结束时被破坏,并且当异步传输实际尝试启动时,该内存已被释放,从而导致段错误。

一般来说,我喜欢将我实际传输和接收的缓冲区作为我的服务器和客户端类的私有成员,以确保它们是静态范围的,并且不会在传输中途意外消失或接收。它可能会占用一些内存,但我发现它让我很安心。如果这种方法没有给您带来任何乐趣,请告诉我,我会看看是否可以在本地重现该错误。 (目前我的“本地复制”尝试包括我破解一个旧的“使用 ASIO 的服务器客户端”示例来分配 TX 缓冲区,如您在上面指出的,然后处理一些内存,所以如果 TX 试图做进一步堆访问应该是段错误。

【讨论】:

  • 您好,谢谢您的回答,因为它只是一个个人程序,我已经搁置了一段时间。问题不在于您的建议,因为该消息仍然有效。当我尝试在Transaction::runThread 的异步调用中访问端点引用时,我收到了段错误错误,尽管我使用复制构造函数创建了它。
猜你喜欢
  • 2013-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多