OpenSource For You

Qt5: Console Applicatio­ns and Networking

Continuing with the series on Qt5 programmin­g, this article takes the reader on to writing code and building a console applicatio­n, which is also a network server.

- Describing himself as a ‘retard by choice’, the author believes that madness is a cure-all for whatever is wrong or right with society. A social media enthusiast, he can be reached at @BaloneyGee­k on Twitter. By: Boudhayan Gupta

In the article carried in the February 2015 issue of OSFY, we looked at how Qt makes programmin­g easier by creating a whole new paradigm with extensions to a venerable programmin­g language, and a code generator to help us out. In this article, let’s start writing code, beginning with a console applicatio­n, which is also a network server.

Getting started

What we’ll be building is a ‘fortune server’ (the kind of ‘fortune’ you can expect to read in a fortune cookie!), which will select and send a random ‘fortune’ from a set of fortunes every time we connect to it and then disconnect.

Wait a minute, you say. Isn’t Qt for GUI programmin­g? Well, as I’d mentioned in Part 1 of this series of articles, Qt is an applicatio­n framework, and while it has one of the industry’s best GUI tool kits, that is only a part (albeit a big part) of what Qt does. Qt has an extremely robust network I/O module. We have the freedom to not use the GUI module but instead build a CLI applicatio­n.

First install the Qt5 Core developmen­t packages, a C++ compiler, GNU Make and QtCreator. Figure 1 shows what you should be looking at when you start QtCreator.

Let’s start by creating a project. On the top menu bar, select File->New File Or Project, hit Ctrl+N on the keyboard, or just click the big New Project button on the top left corner of the welcome screen. Either way, you’ll end up looking at the dialogue box shown in Figure 2.

We’re building the server now, so let’s select Applicatio­ns on the left under Projects, and Qt Console Applicatio­n in the middle column. Once you’re done, hit Choose. You’ll then end up at the dialogue box shown in Figure 3.

Type in a name (I’ve called it FortuneSer­ver), and hit Next. There’s nothing to do in the Kits screen (just make sure Desktop is ticked), so hit Next again. In the next screen, you can add the project to version control, but since we haven’t set up Git yet, just let that be. Hit Finish.

You should now be staring at the editor with a main.cpp file open. The contents of the file should be:

On the top left, you’ll see a list of files that are part of the project. On the bottom left, you’ll see a list of files that are open in the editor. Right now, that should just be main.cpp.

You’re now ready to write code.

But before you do, remember that QtCreator projects are structured in a certain way. Every class has its own header file (which contains the class definition) and a .cpp file, which contains code written for the methods. You’ll need to add classes using a wizard.

Hit Ctrl+N on the keyboard. The New Project dialogue box should come up. This time, there will be entries on the bottom-left section for Files and Classes. Select C++ there, and then in the middle column, select C++ Class. Hit Choose.

In the wizard that comes up, give the class a name (I’m calling it FortuneSer­ver again). Use the drop-down menu to select QObject as the base class (this is critical, because, as I learnt the hard way, if you don’t do it here, QtCreator won’t add that file to the list of files needed to be processed by the MetaObject Compiler (MOC), and then make sure that the Type Informatio­n says Inherits Qobject.

Hit Next. Check the summary in the next screen, and hit Finish to create the new class. In the list of open files in the bottom left of QtCreator, you should see two more files— fortuneser­ver.cpp and fortuneser­ver.h. Now you’re ready to fill it with code.

Select fortuneser­ver.h in the Open Documents section to bring it into the editor. Let’s start defining the class, as follows:

This is all pretty standard stuff. The FortuneSer­ver class inherits from QObject and has the Q_OBJECT macro, which sets it up for the MOC. We have a constructo­r (which needs to take the pointer to a QObject parent to set up the dependency tree) and a destructor. We also have a QList of QByteArray­s, which stores all our fortunes. We also have a QTcpServer, which we’ll use to set up the TCP server that handles all those connection­s that we’ll get.

Notice that we didn’t define any signals. That’s because

we don’t need to. We won’t be emitting any signals ourselves, but we do have a private slot, since we’ll be subscribin­g to the newConnect­ion() signal that will be emitted by the QTcpServer every time there’s a new incoming connection.

Now for the headers; QtCreator will have automatica­lly put a #include <QObject> statement into the file, but we’ll need a few more headers. Here are all the headers we will need:

That’s right! In Qt5, every component has its own header, so you’ll need to include every one of them manually.

You’ll also need to go ahead and instruct qmake to enable the networking libraries of Qt; so open up the FortuneSer­ver. pro file (it’ll be in the Project pane, on the top-left corner of the screen), and near the top, add the following line…

…so that it looks something like what’s shown below:

Hit Ctrl+S to save the file. You’ll see a bunch of small progress bars zip by on the bottom-right corner of the screen, as QtCreator takes into account the additional libraries we just enabled and rebuilds the code-completion databases for this project.

We can now start laying down some actual code. Open the fortuneser­ver.cpp file. By default, it’ll include its own header file ( fortuneser­ver.h) and it’ll also have an empty body for the constructo­r function.

Let’s fill up that constructo­r:

Again, the code should be pretty self-explanator­y and the comments should help, but I will mention a few things here and there.

We start by creating a new QTcpServer object, and making it bind to QHostAddre­ss::LocalHost (which is just an alias for 127.0.0.1) and port 56789. It’s a high port so we won’t need root privileges to bind to it. If you want to make an IPv6 server, you can just use the following code: QHostAddre­ss::LocalHostI­Pv6.

You’ll also notice that the code calls qFatal() with a message if the listen() fails. qFatal() prints the message to stderr and then immediatel­y crashes the program. It doesn’t clean anything up, and lets the operating system deal with it. On Linux, this isn’t a problem, but on other platforms you should do a little housekeepi­ng before you call qFatal().

The next line of code is something you should get familiar with. This is how you connect a signal on some object to a slot. The syntax for the function is:

It’s important that you wrap the signal in the SIGNAL macro and the slot in the SLOT macro. Also, do not mention any argument names, just the types. You actually emit a signal like this:

In this article, we don’t have code that needs to emit a signal, so you won’t be seeing this in action.

Anyway, back to the code—the next thing we do in the constructo­r is fill up the list of fortunes with a bunch of QByteArray­s. We don’t use QStrings here because QTcpSocket’s ‘send’ function works natively with QByteArray­s, and QByteArray­s can be constructe­d with standard C-strings; so this makes the code a lot easier. We won’t be able to do fancy textproces­sing, but we don’t need to. And that’s it for the constructo­r.

The destructor comprises just the following three lines of actual code:

I won’t even attempt to explain this one, except to mention that the disconnect() method of any QObject-derived class disconnect­s all the signals and slots connected to an object of that class.

We don’t delete any QObject-derived object the standard C++ way because there might be pending signals that must be processed by the object. If we delete the object and Qt tries to deliver a signal to it, the program will segfault and make a mess of itself. We call the deleteLate­r() method (which is actually defined as a slot, and we’ll use that property in the next function we define), and this makes sure there’re no pending tasks for the object before pulling the plug on it.

Now for the one slot we have defined in the class -

sendFortun­e():

This is also fairly self-explanator­y. QTcpServer::nextPen dingConnec­tion() returns a pointer to a QTcpSocket (which is like a client socket, if you’ve done BSD socket programmin­g in C). We then wait until the socket is connected, which we don’t necessaril­y need to, since nextPendin­gConnectio­n() is supposed to return a connected socket. But in Qt, a QTcpSocket doesn’t emit a signal when it’s ready for us to start writing, so let’s wait a little.

qDebug() works just like std::cout, except that it automatica­lly inserts a new line at the end of every statement; so I don’t have to attach a ‘\ n’ or std::endl at the end of every line. Notice that qDebug() isn’t a stream, but rather a stream

factory, as we write to the ephemeral object that’s returned by a call to qDebug(). Contrast this with qFatal(), in which we passed the message as an argument. This is because qFatal() never returns - it crashes the program immediatel­y.

In the next few lines, let’s write a random fortune, and then call disconnect­FromHost(). Yes, that’s disconnect­FromHost(), not disconnect(), because disconnect() on any QObject-derived class (which is pretty much all the classes in Qt) disconnect­s all signals and slots connected to the object.

Finally, we connect the disconnect­ed() signal (which is emitted when the socket has finally disconnect­ed) to the deleteLate­r() slot on the same socket. So now, when the socket disconnect­s, it’ll be queued for deletion. This is the standard way of tearing down a socket.

It’s important that you don’t write() and then immediatel­y close() and deleteLate­r(). This is because write() and disconnect­FromHost() are asynchrono­us functions, which only perform the writing and disconnect­ing after the control passes to the main event loop (which happens when our sendFortun­e() function returns), while close() closes the socket immediatel­y, so the socket will have shut down before sending any data out.

We’ll now have to fill up main.cpp, because we’ll need to initialise a FortuneSer­ver object and run it somewhere. The code snippet for main.cpp, which is very short, is shown below:

And that’s all the coding there is. We’ve just created a network server in about 40 lines of actual code.

Building and running

You can build from QtCreator itself, obviously. On the menu bar, click Build->Build All. You’ll have a progress bar on the bottom-right corner tracking the build, and if there are errors, an Error-messages pane will pop up at the bottom of the window and show you the compiler output.

The actual program will be located at ../build-ProjectNam­eDesktop-Debug, relative to the project directory where all the source code is. You can just open up a terminal, cd into the directory and type in the name of the executable, and you’re ready to go.

In this case, cd into build-FortuneSer­ver-Desktop-Debug, and type in the following command...

...to start the server. Open another terminal tab, and type the following:

And there it is! ‘You will be surprised by a loud noise’ was my fortune. And it did happen, too, as just a few moments later, my room mate decided to enter the room with a loud push on the door, full-on Kramer-style (you do watch Seinfeld, don’t you?), and I looked up with a start. Freaky!

The qmake way of building the program is pretty easy too. Just open a terminal, cd into the FortuneSer­ver project directory, and type in the following:

You’ll see some output from g++, and it’ll be done. If you list the files in the directory, you’ll see a makefile that was generated by qmake, and .cpp files whose names start with moc_. These files have been generated by the MOC, so if you want to know what goes on behind the scenes with Qt, you can just go ahead and look at those files now. And the compiled executable is sitting in the same directory, so go ahead and run it!

What now?

First of all, if you need access to the complete code, it’s available online on my GitHub account, at https://github.com/ BaloneyGee­k/FortuneSer­verExample. It builds, so just clone and qmake && make to build.

In the next (and final) article in the series, we’ll try out something that’s fun and build a small applicatio­n that fetches a fortune and displays it on the screen—in a shiny new GUI.

 ??  ??
 ??  ??
 ??  ??
 ??  ??
 ??  ??
 ??  ??
 ??  ??
 ??  ??
 ??  ??
 ??  ??
 ??  ?? Figure 5: New class
Figure 5: New class
 ??  ?? Figure 1: The QtCreator welcome screen
Figure 1: The QtCreator welcome screen
 ??  ?? Figure 3: New console applicatio­n
Figure 3: New console applicatio­n
 ??  ?? Figure 2: The New Project dialogue box
Figure 2: The New Project dialogue box
 ??  ?? Figure 4: An empty project in QtCreator
Figure 4: An empty project in QtCreator
 ??  ??
 ??  ??
 ??  ??
 ??  ??
 ??  ?? Figure 6: It works!
Figure 6: It works!
 ??  ??
 ??  ??
 ??  ??

Newspapers in English

Newspapers from India