Qt:当用户关闭控制台应用程序时检测到 QTcpSocket 断开连接
Qt: Detect a QTcpSocket disconnection in a console app when the user closes it
我的问题标题应该够了。我已经试过了(没有成功):
- 在函数中使用 C-style 析构函数:
__attribute__((destructor))
:
void sendToServerAtExit() __attribute__((destructor)) {
mySocket->write("$%BYE_CODE%$");
}
调用了应用程序析构函数,但套接字已经断开,无法写入服务器。
- 使用标准 C 函数
atexit()
,但 TCP 连接已经丢失,所以我无法向服务器发送任何内容。
atexit(sendToServerAtExit); // is the same function of point 1
我找到的解决方案是每秒检查所有连接的套接字是否仍然连接,但我不想这样做效率低下。这只是一个临时解决方案。另外,我希望其他应用程序(甚至是网络应用程序)可以加入我的控制台应用程序的聊天室,我不想每秒都请求数据。
我该怎么办?
处理以下信号(QTcpSocket
继承自 QAbstractSocket
)
void QAbstractSocket::stateChanged(QAbstractSocket::SocketState socketState)
在调用的插槽中,检查 socketState
是否为 QAbstractSocket::ClosingState
。
QAbstractSocket::ClosingState
表示套接字即将关闭。
您可以将插槽连接到断开信号。
connect(m_socket, &QTcpSocket::disconnected, this, &Class::clientDisconnected);
您还可以使用这样的插槽知道哪个用户已断开连接:
void Class::clientDisconnected
{
QTcpSocket* client = qobject_cast<QTcpSocket*>(sender());
if(client)
{
// Do something
client->deleteLater();
}
else
{
// Handle error
}
}
如果您有连接池,此方法很有用。如果你只有一个连接,你也可以使用它,但不要忘记 client->deleteLater()
.
之后的 nullptr
如果我理解你的问题是正确的,你想通过 TCP 发送数据以通知远程计算机你正在关闭套接字。
从技术上讲,这可以在 Qt 中通过监听 QIODevice::aboutToClose()
或 QAbstractSocket::stateChanged()
信号来完成。
但是,如果您优雅地退出程序并通过向远程计算机发送 FIN
数据包来关闭 QTcpSocket
。这意味着在远程计算机上,
运行 程序将收到 TCP 连接完成的通知。例如,如果远程程序也使用 QTcpSocket
,则 QAbstractSocket::disconnected()
将发出信号。
真正的问题出现在其中一个程序没有正常退出时(崩溃、硬件问题、电缆被拔掉等)。在这种情况下,TCP FIN
数据包将
不会发送,并且远程计算机永远不会收到 TCP 连接的另一端已断开的通知。 TCP 连接将在几分钟后超时。
但是,在这种情况下,您也无法将最后一条数据发送到服务器。
最后唯一的解决办法就是每隔一段时间发送一个"I am here"数据包。尽管你声称它效率低下,但它是一种广泛使用的技术,而且它还有一个优点就是它有效。
我的问题标题应该够了。我已经试过了(没有成功):
- 在函数中使用 C-style 析构函数:
__attribute__((destructor))
:
void sendToServerAtExit() __attribute__((destructor)) { mySocket->write("$%BYE_CODE%$"); }
调用了应用程序析构函数,但套接字已经断开,无法写入服务器。
- 使用标准 C 函数
atexit()
,但 TCP 连接已经丢失,所以我无法向服务器发送任何内容。
atexit(sendToServerAtExit); // is the same function of point 1
我找到的解决方案是每秒检查所有连接的套接字是否仍然连接,但我不想这样做效率低下。这只是一个临时解决方案。另外,我希望其他应用程序(甚至是网络应用程序)可以加入我的控制台应用程序的聊天室,我不想每秒都请求数据。
我该怎么办?
处理以下信号(QTcpSocket
继承自 QAbstractSocket
)
void QAbstractSocket::stateChanged(QAbstractSocket::SocketState socketState)
在调用的插槽中,检查 socketState
是否为 QAbstractSocket::ClosingState
。
QAbstractSocket::ClosingState
表示套接字即将关闭。
您可以将插槽连接到断开信号。
connect(m_socket, &QTcpSocket::disconnected, this, &Class::clientDisconnected);
您还可以使用这样的插槽知道哪个用户已断开连接:
void Class::clientDisconnected
{
QTcpSocket* client = qobject_cast<QTcpSocket*>(sender());
if(client)
{
// Do something
client->deleteLater();
}
else
{
// Handle error
}
}
如果您有连接池,此方法很有用。如果你只有一个连接,你也可以使用它,但不要忘记 client->deleteLater()
.
nullptr
如果我理解你的问题是正确的,你想通过 TCP 发送数据以通知远程计算机你正在关闭套接字。
从技术上讲,这可以在 Qt 中通过监听 QIODevice::aboutToClose()
或 QAbstractSocket::stateChanged()
信号来完成。
但是,如果您优雅地退出程序并通过向远程计算机发送 FIN
数据包来关闭 QTcpSocket
。这意味着在远程计算机上,
运行 程序将收到 TCP 连接完成的通知。例如,如果远程程序也使用 QTcpSocket
,则 QAbstractSocket::disconnected()
将发出信号。
真正的问题出现在其中一个程序没有正常退出时(崩溃、硬件问题、电缆被拔掉等)。在这种情况下,TCP FIN
数据包将
不会发送,并且远程计算机永远不会收到 TCP 连接的另一端已断开的通知。 TCP 连接将在几分钟后超时。
但是,在这种情况下,您也无法将最后一条数据发送到服务器。
最后唯一的解决办法就是每隔一段时间发送一个"I am here"数据包。尽管你声称它效率低下,但它是一种广泛使用的技术,而且它还有一个优点就是它有效。