我正在尝试在 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/