我正在尝试在 c++/gloox 上编写自己的 jabber bot。一切正常,但是当互联网连接中断时 - bot 认为它仍然连接,当连接再次连接时 - 当然 bot 不会响应任何消息。

每次机器人成功连接后,gloox' recv() 都会返回 ConnNoError,即使接口(interface)关闭并拔掉电缆也是如此。

尝试使用阻塞和非阻塞 Gloox 的连接和 recv() ,但都没有任何结果。在不同线程中定期检查 xmpp 服务器的可用性似乎不是一个好主意,那么如何正确检查机器人现在是否已连接?

如果不可能只使用 gloox - 请指出一些好的方法,但让它在 unix 中可用。

最佳答案

我也有同样的问题,找到了 recv 总是重新运行 ConnNoError 的原因。这是我发现的。当连接建立时,recv 调用一个名为 dataAvailable 在 ConnectionTCPBase.cpp 中的函数,它返回

( ( select( m_socket + 1, &fds, 0, 0, timeout == -1 ? 0 : &tv ) > 0 ) && FD_ISSET( m_socket, &fds ) != 0 )

搜索 google, I found this thread ,它说 FD_ISSET( m_socket, &fds ) 会检测到套接字是可读的但不是关闭的...... FD_ISSET( m_socket, &fds ) 的返回值始终为 0,即使网络已关闭。在这种情况下,dataAvailable 的返回值为false,所以下面的代码最终在recv 中返回ConnNoError。
if( !dataAvailable( timeout ) )
{
  m_recvMutex.unlock();
  return ConnNoError;
}

不知道是BUG还是什么,好像不是。

后来我又尝试了另一种方式,直接写socket,如果socket关闭会导致SIGPIPE,捕获该信号,然后使用cleanup断开连接。

我终于找到了一个优雅的解决方案,使用心跳。

在 gloox 线程中,调用 heartBeat(),其中 m_pClient 是指向 gloox::Client 实例的指针
void    CXmpp::heartBeat()
{
    m_pClient->xmppPing(m_pClient->jid(), this);
    if (++heart) > 3) {
        m_pClient->disconnect();
    }
}

xmppPing 将自己注册到 eventhandler,当 ping 回来时,它会调用 handleEvent,并在 handleEvent
void CEventHandler::handleEvent(const Event& event)
{
    std::string sEvent;
    switch (event.eventType())
    {
        case Event::PingPing:
            sEvent = "PingPing";
            break;
        case Event::PingPong:
            sEvent = "PingPong";
            //recieve from server, decrease the count of heart
            --heart;
            break;
        case Event::PingError:
            sEvent = "PingError";
            break;
        default:
            break;
    }
    return;
}

连接到服务器,关闭网络,3 秒后,我断开连接!

关于C++/Gloox : how to check when connection is down?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3543294/

10-09 16:47