📜 ⬆️ ⬇️

Using the SRR mechanism in Qt-designed QNX applications

The Qt framework is one of the most popular and used in the development of cross-platform desktop and mobile applications. This popularity could sooner or later not lead to the use of Qt in systems of special and responsible purposes. For a long time there is the possibility of developing on Qt for QNX Neutrino . The Qt library supports the QNX platform, and the Qt Creator development environment provides interoperability with QNX systems. However, QNX, as a system including for embedded solutions, incorporates technologies that are not required, and therefore are not available in general-purpose systems. The key to the QNX RTOS is the functionality on which the system itself is built and on which user tasks are often based on message passing . The peculiarities of using the SRR mechanism (Send / Receive / Reply), as they also call messaging in QNX, and the development of two examples of Qt applications — client and server — I would like to talk about today.


The note does not make any discoveries, it is proposed in general known information. Nevertheless, Qt is a relatively new framework for developers of special-purpose systems, where historically there has been some inertia in the introduction of new technologies. QNX system developers may not be familiar enough with Qt's intricacies, and Qt application developers may often not know the specifics of QNX. Solving the problem of using in one project both the graphical capabilities of the Qt library and QNX-specific technologies may require effort, especially in the early stages. That is why this note appeared, the purpose of which is to gather information in one place that developers may need when using Qt in QNX.


Typical example of using SRR in QNX


Since I have already written about QNX messages earlier on Habré, including compound messages, we will assume that the theory is already known in some form and we can proceed to practice. Therefore, here are the source code of the client application:


qnx_client.c
//////////////////////////////////////////////////////////////////////////////// // qnx_client.c // // demonstrates using input/output vector (IOV) messaging // //////////////////////////////////////////////////////////////////////////////// #include <string.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include "../iov_server.h" int main(int argc, char* argv[]) { int coid; // Connection ID to server cksum_header_t hdr; // msg header will specify how many bytes of data will follow int incoming_checksum; // space for server's reply int status; // status return value iov_t siov[2]; // create a 2 part iov if ( 2 != argc ) { printf("ERROR: This program must be started with a command-line arg, for example:\n\n"); printf(" iov_client abcdefjhi \n\n"); printf(" where 1st arg(abcdefghi) is the text to be sent to the server to be checksum'd\n"); exit(EXIT_FAILURE); } // locate the server coid = name_open(CKSUM_SERVER_NAME, 0); if ( -1 == coid ) // was there an error attaching to server? { perror("name_open"); // look up error code and print exit(EXIT_FAILURE); } printf("Sending the following text to checksum server: %s\n", argv[1]); // build the header hdr.msg_type = CKSUM_MSG_TYPE; hdr.data_size = strlen(argv[1]) + 1; // setup the message as a two part iov, first the header then the data SETIOV(&siov[0], &hdr, sizeof hdr); SETIOV(&siov[1], argv[1], hdr.data_size); // and send the message off to the server status = MsgSendvs(coid, siov, 2, &incoming_checksum, sizeof incoming_checksum); if ( -1 == status ) // was there an error sending to server? { perror("MsgSend"); exit(EXIT_FAILURE); } printf("received checksum=%d from server\n", incoming_checksum); printf("MsgSend return status: %d\n", status); return EXIT_SUCCESS; } 

The program is quite trivial, I just took an example from the QNX courses and “brushed my hair” a little. This is a console application that accepts a string as input, sends it to the server and displays the server's response — the checksum of the string that was transferred earlier. Note that the example uses compound messages - the SETIOV() macro and the SETIOV() function instead of MsgSend() - which avoids unnecessary copying. The most interesting thing here is the use of the name_open() function to search for a server and establish a connection with it.


Now it's time to look at the source code of the server:


qnx_server.c
 //////////////////////////////////////////////////////////////////////////////// // qnx_server.c // // demonstrates using input/output vector (IOV) messaging // //////////////////////////////////////////////////////////////////////////////// #include <stdio.h> #include <stdlib.h> #include "../iov_server.h" typedef union { uint16_t msg_type; struct _pulse pulse; cksum_header_t cksum_hdr; } msg_buf_t; int calculate_checksum(char *text) { char *c; int cksum = 0; for ( c = text; *c; c++ ) cksum += *c; sleep(10); // emulate calculation delay return cksum; } int main(void) { int rcvid; name_attach_t* attach; msg_buf_t msg; int status; int checksum; char* data; attach = name_attach(NULL, CKSUM_SERVER_NAME, 0); if ( NULL == attach ) { perror("name_attach"); // look up the errno code and print exit(EXIT_FAILURE); } while ( 1 ) { printf("Waiting for a message...\n"); rcvid = MsgReceive(attach->chid, &msg, sizeof(msg), NULL); if ( -1 == rcvid ) // Was there an error receiving msg? { perror("MsgReceive"); // look up errno code and print break; } else if ( rcvid > 0 ) // Process received message { switch ( msg.msg_type ) { case _IO_CONNECT: // name_open() within the client may send this printf("Received an _IO_CONNECT msg\n"); MsgReply(rcvid, EOK, NULL, 0); break; case CKSUM_MSG_TYPE: printf("Received a checksum request msg, header says the data is %d bytes\n", msg.cksum_hdr.data_size); data = malloc(msg.cksum_hdr.data_size); if ( NULL == data ) { MsgError(rcvid, ENOMEM ); } else { status = MsgRead(rcvid, data, msg.cksum_hdr.data_size, sizeof(cksum_header_t)); printf("Received the following text from client: %s\n", data); checksum = calculate_checksum(data); free(data); status = MsgReply(rcvid, EOK, &checksum, sizeof(checksum)); if (-1 == status) { perror("MsgReply"); } } break; default: MsgError(rcvid, ENOSYS); break; } } else if ( 0 == rcvid ) // Process received pulse { switch ( msg.pulse.code ) { case _PULSE_CODE_DISCONNECT: printf("Received disconnect pulse\n"); ConnectDetach(msg.pulse.scoid); break; case _PULSE_CODE_UNBLOCK: printf("Received unblock pulse\n"); break; default: printf("unknown pulse received, code = %d\n", msg.pulse.code); } } else { printf("Receive returned an unexpected value: %d\n", rcvid); } } return 0; } 

The server code is a bit more interesting. The server receives and processes messages from the client. In fact, in this example, only one message is CKSUM_MSG_TYPE - CKSUM_MSG_TYPE - calculation of the checksum of the transmitted data. Another message, _IO_CONNECT is sent to the server when the client calls the name_open() function. In addition to messages, the server can handle service impulses _PULSE_CODE_DISCONNECT and _PULSE_CODE_UNBLOCK . In this simple example, handling of service messages is not required in principle.


The algorithm of the server is quite simple. Initialization is performed first, in this case, the name declaration using the name_attach() function, after which clients can find the server. Further work of the server is an “eternal cycle”. At the very beginning of the cycle, the server is blocked on the MsgReceive() call waiting for messages from the client. When a message or pulse arrives, the QNX kernel unlocks the server, which will begin processing the received message. The example uses the union msg_buf_t to get the message. This is a common practice for QNX, when possible message types (and the message is usually described by the structure of the C language) are combined into a union. Our useful message CKSUM_MSG_TYPE we receive with the help of MsgReceive() not entirely, only the header is received, which indicates the size of the data. The data is read using the MsgRead() function. The response to the client is sent using the MsgReply() function, and in case of an error, it is MsgError() . Impulses do not require an answer.


For completeness, here is the text of the header file. This header file is used by both the server and the client, and, as we will see later, the Qt versions of our server and client also use this file. It is intended to include the necessary header files and the declaration of the message header structure CKSUM_MSG_TYPE .


iov_server.h
 #ifndef _IOV_SERVER_H_ #define _IOV_SERVER_H_ #include <sys/dispatch.h> #include <sys/neutrino.h> #include <sys/iomsg.h> #include <errno.h> #define CKSUM_SERVER_NAME "cksum" #define CKSUM_MSG_TYPE (_IO_MAX + 2) typedef struct { uint16_t msg_type; unsigned data_size; } cksum_header_t; // checksum reply is an int #endif //_IOV_SERVER_H_ 

The screenshot below shows an example of the console versions of the server and client:


image


First, start the server that expects messages from the client. Then the client is started, and the string “Hello, QNX!” Is specified as an argument. During operation, the client and server output diagnostic messages to the console, which can be used to judge the work of the programs. Programs work as expected, you can start writing graphical variants on Qt. First, we adapt the client application.


Qt client example


We will develop Qt applications in Qt Creator. In this case, the process of developing applications for QNX in general does not differ from developing applications for other operating systems. After all, Qt is a cross-platform framework. You only need to create a QNX Kit for Qt Creator.


Create a new application project like Qt Widgets Application. In this case, Qt Creator will prepare all the necessary files, including the form for the window. For the client, the form of the window is as follows:


image


The form contains a text entry field (text) that is sent to the server, connect (connect) and disconnect (disconnect) buttons from the server, a button (calc) to send a message to the server, an input field (cksum), which is used to display the checksum received from server, and the output area of ​​diagnostic messages (status).


It remains only to write the code for working with the server and processing the logic of the graphic form. As a result, we get the following class MainWindow :


mainwindow.h
 #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include "../iov_server.h" namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); public slots: void log(QString msg); void showCrc(QString crc); private slots: void qnxConnect(); void qnxDisconnect(); void calculate(); private: Ui::MainWindow *ui; int coid; // Connection ID to server }; #endif // MAINWINDOW_H 

mainwindow.cpp
 #include "mainwindow.h" #include "ui_mainwindow.h" #include <QDateTime> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); coid = -1; connect(ui->connect, SIGNAL(clicked()), this, SLOT(qnxConnect())); connect(ui->disconnect, SIGNAL(clicked()), this, SLOT(qnxDisconnect())); connect(ui->calc, SIGNAL(clicked()), this, SLOT(calculate())); } MainWindow::~MainWindow() { delete ui; } void MainWindow::qnxConnect() { // check if we already connected if ( coid >= 0 ) return; // connect to the server coid = name_open(CKSUM_SERVER_NAME, 0); if ( coid < 0 ) { log(QString(tr("Can't connect to server: ")).append(strerror(errno))); return; } log(tr("Connected to server")); ui->connect->setEnabled(false); ui->disconnect->setEnabled(true); ui->calc->setEnabled(true); } void MainWindow::qnxDisconnect() { // check if we already disconnected if ( coid < 0 ) return; // disconnect from the server int status = name_close(coid); if ( status < 0 ) { log(QString(tr("Can't disconnect from server: ")).append(strerror(errno))); return; } log(tr("Disconnected from server")); coid = -1; ui->calc->setEnabled(false); ui->disconnect->setEnabled(false); ui->connect->setEnabled(true); } void MainWindow::calculate() { ui->disconnect->setEnabled(false); ui->calc->setEnabled(false); // get the data QString data = ui->text->toPlainText(); log(QString(tr("Sending the following text to checksum server: %1")).arg(data)); // build the header cksum_header_t hdr; // msg header will specify how many bytes of data will follow hdr.msg_type = CKSUM_MSG_TYPE; hdr.data_size = data.length() + 1; // setup the message as a two part iov, first the header then the data iov_t siov[2]; // create a 2 part iov SETIOV(&siov[0], &hdr, sizeof(hdr)); SETIOV(&siov[1], data.toAscii().data(), hdr.data_size); // and send the message off to the server int incoming_checksum; // space for server's reply int status = MsgSendvs(coid, siov, 2, &incoming_checksum, sizeof(incoming_checksum)); if ( status < 0 ) { log(QString(tr("Can't send message to server: ")).append(strerror(errno))); return; } log(QString(tr("MsgSend return status: %1")).arg(status)); showCrc(QString::number(incoming_checksum)); } void MainWindow::showCrc(QString crc) { ui->cksum->setText(crc); ui->disconnect->setEnabled(true); ui->calc->setEnabled(true); } void MainWindow::log(QString msg) { ui->status->append(msg.prepend(QDateTime::currentDateTime().toString("hh:mm:ss "))); } 

The main.cpp file remains the way Qt Creator created it, so I will not list its contents.


So, let's see what we have done here. First, as in the previous example, we start the server. Then run the Qt client version. Press the Connect button, note that the server receives a notification about the client connection in the form of a _IO_CONNECT message. Then we write the text “Hello, QNX!” And press the Calc button, which causes the message to be sent to the server. The send event is also displayed on the screen. The checksum received from the server is displayed in the client window.


image


The example works, messages are sent and received, no problems were noticed. But ... But I know that everything should not work so well. The fact is that after calling MsgSendvs() client is blocked at least until the server calls the MsgReceive() function (it can be more if there are higher-priority processes in the system). To illustrate this feature, a delay in the form of the sleep(10) call has been added to the server's calculate_checksum() function code. With such a delay in the server, the client is blocked for 10 seconds, which leads to a noticeable "freezing" of the graphical server window.


In some cases, especially when the server responds immediately to the client (i.e., the information is always available to the server, and does not come from the outside), locking is not a problem. In other cases, the user may become nervous when his GUI freezes. I would not risk and release programs that can irritate customers. With the “frozen” interface, the client will not be able to continue working with the application after sending the message before receiving a response from the server, and in real life the application can interact with several servers and provide other management functions. No, the current version of the client application does not suit us. So let's look at the correct implementation of the client.


Right Qt client example


How can you solve the problem with locking the client? The client can not be blocked on MsgSendvs() . However, it is quite possible to allocate work with messages in a separate thread. In this case, one thread serves a graphical interface, the other implements the SRR mechanism. To work with threads in Qt, we will use the QThread class. The SRR implementation will be rendered into a separate Sender class. The relationship between the Sender classes (work with messages) and MainWindow (graphical interface) is organized through Qt signals and slots.


Let's see how the MainWindow class has changed, taking into account the above. For clarity, the old code is also retained, and the SENDER_THREAD macro has been added, when declaring which work with messages is performed in a separate Qt thread.


mainwindow.h
 #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include "../iov_server.h" #define SENDER_THREAD #ifdef SENDER_THREAD #include <QThread> #endif namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); #ifdef SENDER_THREAD signals: void calcCrc(int coid, QString data); #endif public slots: void log(QString msg); void showCrc(QString crc); private slots: void qnxConnect(); void qnxDisconnect(); void calculate(); private: Ui::MainWindow *ui; int coid; // Connection ID to server #ifdef SENDER_THREAD QThread senderThread; #endif }; #endif // MAINWINDOW_H 

mainwindow.cpp
 #include "mainwindow.h" #include "ui_mainwindow.h" #ifdef SENDER_THREAD #include "sender.h" #endif #include <QDateTime> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); coid = -1; connect(ui->connect, SIGNAL(clicked()), this, SLOT(qnxConnect())); connect(ui->disconnect, SIGNAL(clicked()), this, SLOT(qnxDisconnect())); connect(ui->calc, SIGNAL(clicked()), this, SLOT(calculate())); #ifdef SENDER_THREAD Sender *sender = new Sender; sender->moveToThread(&senderThread); connect(&senderThread, SIGNAL(finished()), sender, SLOT(deleteLater())); connect(this, SIGNAL(calcCrc(int, QString)), sender, SLOT(send(int, QString))); connect(sender, SIGNAL(result(QString)), this, SLOT(showCrc(QString))); connect(sender, SIGNAL(log(QString)), this, SLOT(log(QString))); senderThread.start(); #endif } MainWindow::~MainWindow() { #ifdef SENDER_THREAD senderThread.quit(); senderThread.wait(); #endif delete ui; } void MainWindow::qnxConnect() { // check if we already connected if ( coid >= 0 ) return; // connect to the server coid = name_open(CKSUM_SERVER_NAME, 0); if ( coid < 0 ) { log(QString(tr("Can't connect to server: ")).append(strerror(errno))); return; } log(tr("Connected to server")); ui->connect->setEnabled(false); ui->disconnect->setEnabled(true); ui->calc->setEnabled(true); } void MainWindow::qnxDisconnect() { // check if we already disconnected if ( coid < 0 ) return; // disconnect from the server int status = name_close(coid); if ( status < 0 ) { log(QString(tr("Can't disconnect from server: ")).append(strerror(errno))); return; } log(tr("Disconnected from server")); coid = -1; ui->calc->setEnabled(false); ui->disconnect->setEnabled(false); ui->connect->setEnabled(true); } void MainWindow::calculate() { ui->disconnect->setEnabled(false); ui->calc->setEnabled(false); // get the data QString data = ui->text->toPlainText(); #ifdef SENDER_THREAD emit calcCrc(coid, data); #else log(QString(tr("Sending the following text to checksum server: %1")).arg(data)); // build the header cksum_header_t hdr; // msg header will specify how many bytes of data will follow hdr.msg_type = CKSUM_MSG_TYPE; hdr.data_size = data.length() + 1; // setup the message as a two part iov, first the header then the data iov_t siov[2]; // create a 2 part iov SETIOV(&siov[0], &hdr, sizeof(hdr)); SETIOV(&siov[1], data.toAscii().data(), hdr.data_size); // and send the message off to the server int incoming_checksum; // space for server's reply int status = MsgSendvs(coid, siov, 2, &incoming_checksum, sizeof(incoming_checksum)); if ( status < 0 ) { log(QString(tr("Can't send message to server: ")).append(strerror(errno))); return; } log(QString(tr("MsgSend return status: %1")).arg(status)); showCrc(QString::number(incoming_checksum)); #endif } void MainWindow::showCrc(QString crc) { ui->cksum->setText(crc); ui->disconnect->setEnabled(true); ui->calc->setEnabled(true); } void MainWindow::log(QString msg) { ui->status->append(msg.prepend(QDateTime::currentDateTime().toString("hh:mm:ss "))); } 

The calcCrc() signal appeared in the declaration of the MainWindow class, with which we tell an instance of the Sender class to whom and what message we need to send.


The implementation of the MainWindow class has undergone major changes. A block of code has appeared in the constructor, in which an instance of the Sender class is created and, using the moveToThread() method, is allocated to a separate thread. In the destructor, we expect the thread to end (the quit() and wait() QThread class). The entire code of the calculate() method has been moved to the Sender class and replaced with the generation of the calcCrc() signal.


After finalizing the MainWindow , you can go to the Sender class.


sender.h
 #ifndef SENDER_H #define SENDER_H #include <QObject> #include "../iov_server.h" class Sender : public QObject { Q_OBJECT public: Sender() {} virtual ~Sender() {} signals: void result(QString data); void log(QString err); public slots: void send(int coid, QString data); }; #endif // SENDER_H 

sender.cpp
 #include "sender.h" void Sender::send(int coid, QString data) { emit log(QString(tr("Sending the following text to checksum server: %1")).arg(data)); // build the header cksum_header_t hdr; // msg header will specify how many bytes of data will follow hdr.msg_type = CKSUM_MSG_TYPE; hdr.data_size = data.length() + 1; // setup the message as a two part iov, first the header then the data iov_t siov[2]; // create a 2 part iov SETIOV(&siov[0], &hdr, sizeof(hdr)); SETIOV(&siov[1], data.toAscii().data(), hdr.data_size); // and send the message off to the server int incoming_checksum; // space for server's reply int status = MsgSendvs(coid, siov, 2, &incoming_checksum, sizeof(incoming_checksum)); if ( status < 0 ) { emit log(QString(tr("Can't send message to server: ")).append(strerror(errno))); return; } emit log(QString(tr("MsgSend return status: %1")).arg(status)); emit result(QString::number(incoming_checksum)); } 

In essence, this is the code that was previously in the calculate() method of the MainWindow class. The output of errors and results in the graphical window of the client application is implemented using the signals log() and result() .


With such modifications, the client’s graphical interface does not “freeze”, i.e. while the Sender class instance is blocked for 10 seconds in a separate thread, we can control the graphic window. However, in the presented example there is nothing to control, but the possibility is there.


Sample Qt Server


After experimenting with the client, we will immediately develop the server correctly. Since the MsgReceive() call causes blocking, we will move the server functionality to the Server class, which will work in a separate thread. The principles are the same as in the client. The honest window “skomunichd” form of the client - copy mainwindow.ui, open it in the editor, remove unnecessary buttons and convert the QPlainTextEdit class (text object) into QTextBrowser (the editor allows it).


image


The declaration and implementation of the server's MainWindow class are listed below:


mainwindow.h
 #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QThread> #include "../iov_server.h" namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); signals: void startServer(name_attach_t* attach); public slots: void log(QString msg); void showCrc(QString crc); void showText(QString txt); void stopServer(void); private: Ui::MainWindow *ui; name_attach_t* attach; QThread serverThread; }; #endif // MAINWINDOW_H 

mainwindow.cpp
 #include "mainwindow.h" #include "ui_mainwindow.h" #include "server.h" #include <QDateTime> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); Server *server = new Server; server->moveToThread(&serverThread); connect(&serverThread, SIGNAL(finished()), server, SLOT(deleteLater())); connect(this, SIGNAL(startServer(name_attach_t*)), server, SLOT(process(name_attach_t*))); connect(server, SIGNAL(result(QString)), this, SLOT(showCrc(QString))); connect(server, SIGNAL(text(QString)), this, SLOT(showText(QString))); connect(server, SIGNAL(log(QString)), this, SLOT(log(QString))); attach = name_attach(NULL, CKSUM_SERVER_NAME, 0); if ( NULL == attach ) { log(QString(tr("Can't attach name: %1")).arg(strerror(errno))); } else { serverThread.start(); emit startServer(attach); } } MainWindow::~MainWindow() { stopServer(); serverThread.quit(); serverThread.wait(); delete ui; } void MainWindow::showText(QString txt) { ui->text->setText(txt); } void MainWindow::showCrc(QString crc) { ui->cksum->setText(crc); } void MainWindow::log(QString msg) { ui->status->append(msg.prepend(QDateTime::currentDateTime().toString("hh:mm:ss "))); } void MainWindow::stopServer() { if ( NULL != attach ) { name_detach(attach, 0); } } 

For server operation, create a name in MainWindow using the function name_attach() . With the help of a signal, we pass the attach structure to the server thread, thereby starting it. To stop the server, delete the name - the function name_detach() . The rest is very similar to what was done in the client. Let's look at the code:


server.h
 #ifndef SERVER_H #define SERVER_H #include <QObject> #include "../iov_server.h" typedef union { uint16_t msg_type; struct _pulse pulse; cksum_header_t cksum_hdr; } msg_buf_t; class Server : public QObject { Q_OBJECT public: Server() {} virtual ~Server() {} signals: void result(QString data); void text(QString text); void log(QString err); public slots: void process(name_attach_t* attach); private: int calculate_checksum(char *text); }; #endif // SERVER_H 

server.cpp
 #include "server.h" int Server::calculate_checksum(char *text) { int cksum = 0; for ( char *c = text; *c; c++ ) cksum += *c; sleep(10); // emulate calculation delay return cksum; } void Server::process(name_attach_t* attach) { if ( NULL == attach ) { return; } int rcvid; msg_buf_t msg; char *data; while ( 1 ) { emit log(tr("Waiting for a message...")); rcvid = MsgReceive(attach->chid, &msg, sizeof(msg), NULL); if ( -1 == rcvid ) // Was there an error receiving msg? { emit log(QString(tr("MsgReceive: %1")).arg(strerror(errno))); // look up errno code and print break; } else if ( rcvid > 0 ) // Process received message { switch ( msg.msg_type ) { case _IO_CONNECT: // name_open() within the client may send this emit log(tr("Received an _IO_CONNECT msg")); MsgReply(rcvid, EOK, NULL, 0); break; case CKSUM_MSG_TYPE: emit log(QString(tr("Received a checksum request msg, header says the data is %1 bytes")).arg(msg.cksum_hdr.data_size)); data = (char *)malloc(msg.cksum_hdr.data_size); if ( NULL == data ) { MsgError(rcvid, ENOMEM ); } else { int status = MsgRead(rcvid, data, msg.cksum_hdr.data_size, sizeof(cksum_header_t)); emit text(data); int checksum = calculate_checksum(data); emit result(QString::number(checksum)); free(data); status = MsgReply(rcvid, EOK, &checksum, sizeof(checksum)); if (-1 == status) { emit log(tr("MsgReply")); } } break; default: MsgError(rcvid, ENOSYS); break; } } else if ( 0 == rcvid ) // Process received pulse { switch ( msg.pulse.code ) { case _PULSE_CODE_DISCONNECT: emit log(tr("Received disconnect pulse")); ConnectDetach(msg.pulse.scoid); break; case _PULSE_CODE_UNBLOCK: emit log(tr("Received unblock pulse")); break; default: emit log(QString(tr("unknown pulse received, code = %1")).arg(msg.pulse.code)); } } else { emit log(QString(tr("Receive returned an unexpected value: %1")).arg(rcvid)); } } } 

The Server class implements two console server functions (qnx_server), only the output of messages has changed (using Qt signals / slots) and the name is registered in the MainWindow class. The work of the graphical variants of the client and server is presented in the following screenshot:


image


The server turned out without controls. There are no buttons or input fields. The graphical server window serves only to monitor its operation.


Conclusion


That came to an end this note. The code of several examples was considered, it became clear how to correctly use the QNX message mechanism in Qt applications. For those who want to reproduce the examples, I published them on Bitbucket . Anticipating possible comments on the code, please note that these are only examples that illustrate the operation of SRR in Qt. I would have done something differently in the working system, but in order not to overload the examples, their code was simplified, and for some moments I closed my eyes. Nevertheless, if someone from the readers has specific suggestions for improving the code of examples or correcting errors, I will consider them if possible. I ask on these issues to contact private messages.


')

Source: https://habr.com/ru/post/305680/


All Articles