0

My question title should be enough. I already tried (without success):

  1. Using a C-style destructor in a function: __attribute__((destructor)):
    void sendToServerAtExit() __attribute__((destructor)) { mySocket->write("$%BYE_CODE%$"); }

The application destructor is called, but the socket is already disconnected and I can't write to the server.

  1. Using the standard C function atexit(), but the TCP connection is already lost so I can't send anything to the server.
    atexit(sendToServerAtExit); // is the same function of point 1

The solution I found is check every second if all connected sockets are still connected, but I don't want to do so inefficient thing. It's only a temporary solution. Also, I want that others apps (even web ones) can join the chat room of my console app, and I don't want to request data every second.

What should I do?

3 Answers3

2

Handle the below signal (QTcpSocket is inherited from QAbstractSocket)

void QAbstractSocket::stateChanged(QAbstractSocket::SocketState socketState)

Inside the slot called, check if socketState is QAbstractSocket::ClosingState.

QAbstractSocket::ClosingState indicates the socket is about to close.

http://doc.qt.io/qt-5/qabstractsocket.html#SocketState-enum

Pavan Chandaka
  • 11,671
  • 5
  • 26
  • 34
1

You can connect a slot to the disconnect signal.

connect(m_socket, &QTcpSocket::disconnected, this, &Class::clientDisconnected);

Check the documentation.

You can also know which user has been disconnected using a slot like this:

void Class::clientDisconnected
{
    QTcpSocket* client = qobject_cast<QTcpSocket*>(sender());
    if(client)
    {
        // Do something
        client->deleteLater();
    }
    else
    {
        // Handle error
    }
}

This method is usefull if you have a connections pool. You can use it as well if you have a single connection, but do not forget nullptr after client->deleteLater().

albertTaberner
  • 1,969
  • 1
  • 26
  • 35
  • The question is about sending data before the socket is closed. The `disconnected()` signal is emitted to late. – Benjamin T Nov 08 '17 at 09:04
  • Then you should implement a pre-disconnection mechanism from your client side. Even the "about to disconect" qtcpsocket state is not valid, since client will not be listening for new incoming bytes. – albertTaberner Nov 08 '17 at 09:19
1

If I understand you question correctly, you want to send data over TCP to notify the remote computer that you are closing the socket.

Technically this can be done in Qt by listenning to the QIODevice::aboutToClose() or QAbstractSocket::stateChanged() signals.

However, if you graciously exit your program and close the QTcpSocket by sending a FIN packet to the remote computer. This means that on the remote computer, the running program will be notified that the TCP connection finished. For instance, if the remote program is also using QTcpSocket, the QAbstractSocket::disconnected() signal will be emitted.

The real issues arise when one of the program does not graciously exit (crash, hardware issue, cable unplugged, etc.). In this case, the TCP FIN packet will not be sent and the remote computer will never get notified that the other side of the TCP connection is disconnected. The TCP connection will just time-out after a few minutes. However, in this case you cannot send your final piece of data to the server either.

In the end the only solution is to send a "I am here" packet every now and then. Even though you claim it is ineficient, it is a widely used technique and it also has the advantage that it works.

Benjamin T
  • 8,120
  • 20
  • 37