Why doesn't QApplication handle SIGTERM (and any other) signal and exit gracefully? Are there any good reasons not to do it?
Related
I have a Qt-based library which has an object that emits signals, but also does some stuff asynchronously behind the scenes.
It is possible for the user of the library to connect the signal being emitted by the object using Qt::DirectConnection or Qt::BlockingQueuedConnection, which will hijack the object's dedicated thread and therefore, and potentially break its functionality.
Is there a way of only allowing for the signal to be connected using a given type of connection? Qt::QueuedConnection, to be specific. Such that the user gets a compilation error when they try to use any other type of connection.
You can use a proxy signal that you declare in the public interface and connect your own internal signals to that signal using queued connection. Thus, the user will be able to use this signal in any way (direct or queued), but it will be already emitted by queued connection.
Since signals can't be private, there is no way to hide them once they are declared in a class.
One solution is to use PIMPL to hide your internal signals from the user. The example shows only queued connection between signals, but not the PIMPL:
#include <QObject>
class InternalSignal : public QObject
{
Q_OBJECT
public:
explicit InternalSignal(QObject *parent = nullptr) : QObject{parent} {
connect(this, &InternalSignal::myPIMPLSignal, this, &InternalSignal::mySignal, Qt::QueuedConnection);
}
signals:
void mySignal();
void myPIMPLSignal(); // move this signal to PIMPL class
};
Currently our tool uses QTCPSocket->ConnectToHost to connect to our TCP server, which works.
The problem arises when some of our machines are bridging two networks, across two entirely different IP ranges (10.x.x.x, 172.x.x.x). When you try to connect to a device on the 172.x.x.x network, it appears to be trying to connect via the 10.x network interface, and then times out and fails to connect. On windows, if you disable the network port for the 10.x network and reload the tool, it correctly uses the 172.x network interface and connects. I can see no way with QTCPSocket to force it to connect using a specific interface, or am I missing something? It seems like the 10.x network is getting priority somehow and we always try to use that when trying to establish an outgoing connection, which is not what we want.
Ideally, the user would be able to select what network interface they want to use to make the connection, whether its the 10.x or 172.x network.
This is using QT 5.15.0.
You can select the outgoing interface to use by calling bind() with your interfaces address first. This will select your outgoing address to use.
See the documentation for the bind function:
For TCP sockets, this function may be used to specify which interface to use for an outgoing connection, which is useful in case of multiple network interfaces.
I threw together a very simple demo for you:
Its all running locally. This is the servers main.cpp:
#include <QCoreApplication>
#include <QTcpServer>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QTcpServer serv;
QObject::connect(&serv, &QTcpServer::newConnection, [](){
qDebug() << "New connection!";
});
qDebug() << serv.listen(QHostAddress("192.168.x.y"), 1337);
return a.exec();
}
And this is the clients main.cpp:
#include <QCoreApplication>
#include <QDebug>
#include <QTcpSocket>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QTcpSocket s;
qDebug() << s.bind(QHostAddress("127.0.0.1"));
s.connectToHost(QHostAddress("192.168.x.y"), 1337);
return a.exec();
}
By calling bind we tell the client to send packets using the local interface, but as the server only listens to my wifi interface 192.168.x.y the connection will fail. If you now change the following line:
qDebug() << s.bind(QHostAddress("127.0.0.1"));
as such:
qDebug() << s.bind(QHostAddress("192.168.x.y"));
You will see that the server will recieve the connection, as we explicitly selected this interface to send from.
However, the operating system should select the correct interface for you (meaning in the demo: by not calling bind you should get a connection). If that does not happen you have a different issue.
To get a list of all available interfaces you can use QNetworkInterface::allInterfaces() which will grant you access to everything might you need to know.
I'm working on some application using Qt framework, it uses serial port and need to receive some data, problem is that data is organized with some protocol, which i parse in readyRead() signal handler(slot), at the same time, i need to wait for parsed message with some timeout. So, to wait, i use QThread::msleep() after sending, but i've noticed, that when thread goes to sleep in msleep(), readyRead will be emitted only after msleep() will be finished. My question is, why readyRead can't wake up thread? Qt signal is not working like real Unix signals?
If you have single thread application readyRead slot not executes immediatly you got data on port. Read about Qt::QueuedConnection in QObject::connect(). When readyRead signal emits in serial port class it just added to queue of events (in global event loop). All events will be executed later by QEventLoop (inside QApplication instance).
Looks like you sleep your main thread so QEventLoop cant execute anything while sleeping. In this case you need to read your port from another thread to avoid main thread sleeping.
I am writing a simple network application that will be sending and receiving TCP messages to a single listener. I use a context class to wrap much of the communication logic as such:
class context : public QObject
{
Q_OBJECT
public:
void setDevice (unique_ptr<QIODevice> device);
void sendMessage (message msg);
signals:
void newMessage (message msg);
private:
unique_ptr<QIODevice> m_device;
}
A generic QIODevice is given to the object instead of the concrete subtype QTcpConnection so that the logic can be tested without a network connection. I expected that any network errors would be presented as IO errors from the QIODevice. However, if the host disconnects, the QIODevice does not emit a signal. The QTcpConnection does emit a signal (disconnected) but the underlying QIODevice remains open, continues to allow reads and writes, and does not appear to give any notification of the error. My confirmation that the socket does see the disconnect is that the error string in QIODevice changes from "Unknown error" to "Socket is not connected"; but checking for an error string seems like a hack that shouldn't be necessary.
Is there actually some way to detect this kind of error with only the base class? If I am required to pass in the QTcpSocket, is there a way that I can still keep unit tests that do not require a client-server connection?
I am having a method and signal. From one process which is developed in Qt Creator 5.2.1, has 1 method and 1 signal.
The method is called using QDbusConnection and QDbusMessage.
The signal is connected with one slot.
A remote application which is to be developed in C should call the method remotely and should emit signal.
I need to know the sequence to remotely run the method and the sequence to emit signal.
Please help me the sequence in C program. No clear picture I found while surfing in internet.