Please advise how can I setup default connection timeout without using blocking waitForConnected() method? I noticed that socket emit error signal (QAbstractSocket::SocketTimeoutError) after about 60 seconds that I can handle as a timeout, but can this timeout be adjusted?
You could use a QTimer:
Start it after you have called connectToHost.
You may want to reset the timer when socket state changes from QAbstractSocket::HostLookupState to QAbstractSocket::ConnectingState, perhaps with different timeout, if you want more fine-grained control on when exactly will the timeout happen.
If you get connection, stop the timer, or reset it for similar send/receive timeout use.
If you get timer timeout, do disconnectFromHost() and possibly do something like retry when you get disconnect signal.
When developing, make sure to connect the stateChanged(...) and error(...) signals at least to debug slots, which just print the arguments. That way you will see when something happens in a way you did not expect.
Related
My question title should be enough. I already tried (without success):
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.
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?
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
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().
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.
I have a process which is already in signal handler , and called a process blocking call. What will happen if one more signal arrives for this process ?
By default signals don't block each other. A signal only blocks itself during its own delivery. So, in general, an handling code can be interrupted by another signal delivery.
You can control this behavior by setting the process signal mask relatively to each signal delivery. This means that you can block (or serialize) signal delivery. For instance you can declare that you accept to be interrupted with signal S1 while handling signal S2, but not the converse...
Remember that signal delivery introduces some concurrency into your code, so controlling the blocking is needed.
I'm pretty sure signals are blocked while a handler is being executed, but I'm having a hard time finding something that says that definitively.
Also, you may wish to see this question - some of the answers talk about what functions you should and shouldn't call from a signal handler.
In general, you should consider a signal handler like an interrupt handler - do the very least you can in the handler, and return quickly.
Qt 4.8, Windows XP:
I have a thread that manages my TCP messages and opens / maintains / closes the socket at the appropriate times.
This same thread starts a QTimer, 200 ms, defined in my thread's data, that pumps an event in my thread's class once (if) the socket is open. So the timer and its event belong to the thread, as best I understand the idea.
The QTimer timeout event sends a TCP message through the port belonging to the thread, it's a keep-alive message for this particular hardware item. Has to be sent regularly or the device "goes away" which won't do.
When the message is sent, I get this error:
"QSocketNotifier: socket notifiers cannot be enabled from another thread"
As far as I can tell, I am sending the message from the same thread and would expect any signals, etc., to be owned / handled etc. by it.
Can anyone tell me what I'm missing here?
PS: The message is sent, the device does stay alive... it's just that I'm getting this runtime error on the Qt error console and I'm very concerned that there are internal problems lurking because of it.
The message does NOT occur running under OS X 10.6. I don't know why.
Ok, here's the scoop. QTimer, for reason only known to the designers of QT, inherits the context of the parent of the thread. Not the context of the thread it's launched from. So when the timer goes off, and you send a message from the slot it called, you're not in the thread's context, you're in the parents context.
You also can't launch a thread that is child of THAT thread, so that you can fire a timer that will actually be in the thread you want. Qt won't let it run.
So, spend some memory, make a queue, load the message into the queue from elsewhere, watch the queue in the thread that owns the TCP port, and send em when ya got em. That works.
I have written a multithreaded application in C. I have two threads created, one for catching all the signals and another for accept()-ing client connections. When I kill the appilcation using killproc, the thread with the accept call is not interrupted. How can I fix that?
The code looks like:
int stop_exec=0;
sigCatcherThread()
{
int sig
sigset_t allsignals;
sigfillset(allsignals);
do{
sigwait(&allsignals, &sig);
if(sig==SIGTERM)
stop_exec=1;
}while(!stop_exec)
}
clientHandler()
{
...
while(!stop_exec)
{
accept(...);
}
main()
{
pthread_create(..., sigCatcherThread,..);
pthread_create(..., clientHandler,...);
}
Here you see the use of interrupted system calls. But the convenience of a signal handling thread is probably higher than the use of interrupted systems calls.
So you need you client handler to block until it can accept an incoming connection or the signal occurs. Waiting for potential input means either signal driven IO -- a path I wouldn't follow -- or select(2) (or pool). But select(2) can wait only on IO. So transform your signal occurrence in IO: open a pipe, have your signal handling thread write to the pipe when SIGQUIT occurs and have your client thread select(2) for the socket and the other end of the pipe.
Only one thread receives a signal targeted to a process. So, it must be not the thread blocked on accept(). See signal concepts for more details.
As already mentioned here, you should probably be using an event loop based on select(). I would suggest using libevent.
There's no need to interrupt the blocking accept call. Just make sure that if the thread does return from accept, say by receiving an actual connection, it won't do anything harmful.
If there's some specific reason you need the accept call to interrupt, explain what it is. Likely there's a simple way to remove the requirement.
If a tcp server and client are connected, I'd like to determine when the client is no longer connected. I thought I can simply do this by attempting to send a message to the client and once send() returns with a -1, I can then tear down the socket. This implementation works find on Windows but the minute I try doing this on Linux with BSD sockets, the call to send() on the server side app causes my server app to crash if the client is no longer connected. It doesn't even return a -1...just terminates the program.
Please explain why this is happening. Thanks in advance!
This is caused by the SIGPIPE signal. See send(2):
The send() function shall fail if:
[EPIPE]
The socket is shut down for writing, or the socket is connection-mode and is no longer connected. In the latter case, and if the socket is of type SOCK_STREAM or SOCK_SEQPACKET and the MSG_NOSIGNAL flag is not set, the SIGPIPE signal is generated to the calling thread.
You can avoid this by using the MSG_NOSIGNAL flag on the send() call, or by ignoring the SIGPIPE signal with signal(SIGPIPE, SIG_IGN) at the beginning of your program. Then the send() function will return -1 and set errno to EPIPE in this situation.
You need to ignore the SIGPIPE signal. If a write error happens on a socket, your process with get SIGPIPE, and the default behavior of that signal is to kill your process.
Writing networking code on *nix you usually want:
signal(SIGPIPE,SIG_IGN);