Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QTcpServer with multiple persistent connections
Forum Update on Monday, May 27th 2025

QTcpServer with multiple persistent connections

Scheduled Pinned Locked Moved Unsolved General and Desktop
43 Posts 5 Posters 10.6k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • JonBJ JonB

    @kshegunov

    Without going into too much details about the internals, if the data stream couldn't read the whole block QDataStream::commitTransaction will fail

    That's the bit I wasn't sure about and had to guess! So, "Without going into too much details", how does it decide that (and where is it documented for us plebs)? Like, does it implement a timeout of some nature?

    kshegunovK Offline
    kshegunovK Offline
    kshegunov
    Moderators
    wrote on last edited by kshegunov
    #14

    @JonB said in QTcpServer with multiple persistent connections:

    how does it decide that (and where is it documented for us plebs)?

    The method docs, I guess? Too lazy to check to be honest.
    The decision is made based on the QDataStream status. Whenever you're writing/reading from the stream, e.g. when you provide serialization for the objects (think << and >> operators) you can (and should) set the status if the (de)serialization failed. This is already done for the Qt types anyway. Here, simply reading a byte array, the validation is rather straight-forward (internal to Qt):

    1. Try to read the buffer size (i.e. an integer). If there's not enough data on the QIODevice to read an integer, the operation fails.
    2. Try to read the actual buffer contents (you already know the size from 1). If there's not enough data on the device, the operation fails.

    Like, does it implement a timeout of some nature?

    No, it's simpler than that. The data is buffered in the socket object. So you just try to read it from that memory buffer. If reading fails, the transaction fails. If reading succeeds the buffer is "shortened" with the data you read. The buffer is filled asynchronously by Qt whenever the data comes through the underlying system socket.

    Read and abide by the Qt Code of Conduct

    JonBJ 1 Reply Last reply
    2
    • kshegunovK kshegunov

      @JonB said in QTcpServer with multiple persistent connections:

      how does it decide that (and where is it documented for us plebs)?

      The method docs, I guess? Too lazy to check to be honest.
      The decision is made based on the QDataStream status. Whenever you're writing/reading from the stream, e.g. when you provide serialization for the objects (think << and >> operators) you can (and should) set the status if the (de)serialization failed. This is already done for the Qt types anyway. Here, simply reading a byte array, the validation is rather straight-forward (internal to Qt):

      1. Try to read the buffer size (i.e. an integer). If there's not enough data on the QIODevice to read an integer, the operation fails.
      2. Try to read the actual buffer contents (you already know the size from 1). If there's not enough data on the device, the operation fails.

      Like, does it implement a timeout of some nature?

      No, it's simpler than that. The data is buffered in the socket object. So you just try to read it from that memory buffer. If reading fails, the transaction fails. If reading succeeds the buffer is "shortened" with the data you read. The buffer is filled asynchronously by Qt whenever the data comes through the underlying system socket.

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by JonB
      #15

      @kshegunov
      OK, so in a word, QDataStream::commitTransaction() fails/rolls back if there is not enough data already there at the instant it is called, period.

      BTW: so if I decide to transfer a 1GB (or more) file content as one QByteArray, and it arrives in chunks, your transaction approach will have to buffer up to 1GB of previously-received bytes, and that's presumably in memory? Hmmmm. Nobody finds that a problem?

      VRoninV kshegunovK 2 Replies Last reply
      0
      • JonBJ JonB

        @kshegunov
        OK, so in a word, QDataStream::commitTransaction() fails/rolls back if there is not enough data already there at the instant it is called, period.

        BTW: so if I decide to transfer a 1GB (or more) file content as one QByteArray, and it arrives in chunks, your transaction approach will have to buffer up to 1GB of previously-received bytes, and that's presumably in memory? Hmmmm. Nobody finds that a problem?

        VRoninV Offline
        VRoninV Offline
        VRonin
        wrote on last edited by VRonin
        #16

        @JonB said in QTcpServer with multiple persistent connections:

        OK, so in a word, QDataStream::commitTransaction() fails/rolls back if there is not enough data already there at the instant it is called, period.

        Correct

        so if I decide to transfer a 1GB (or more) file content as one QByteArray, and it arrives in chunks, your transaction approach will have to buffer up to 1GB of previously-received bytes, and that's presumably in memory? Hmmmm. Nobody finds that a problem?

        In this case you are free to build your own buffer (i'll use the chat example again):

        1. add a private QTemporaryFile m_dataBuffer; to ChatClient;
        2. in the constructor of ChatClient call m_dataBuffer.open();
        3. modify ChatClient::onReadyRead() as below
        void ChatClient::onReadyRead()
        {
            const qint64 oldPos = m_dataBuffer.pos(); // save the position in the file
            m_dataBuffer.seek(m_dataBuffer.size()); // go to the end of the file
            m_dataBuffer.write(m_clientSocket.readAll()); // append all the data available on the socket into the file
            m_dataBuffer.seek(oldPos); // go back to the old position
            QDataStream socketStream(m_dataBuffer); // set the stream to read from the file
            
        ////////////////////////////////////////////////////////////////////
        // identical to the original version
            QByteArray jsonData;
            socketStream.setVersion(QDataStream::Qt_5_7);
            for (;;) {
                socketStream.startTransaction();
                socketStream >> jsonData;
                if (!socketStream.commitTransaction())
                    break;
                QJsonParseError parseError;
                const QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &parseError);
                if (parseError.error == QJsonParseError::NoError) {
                    if (jsonDoc.isObject())
                        jsonReceived(jsonDoc.object());
                }
            }
        ////////////////////////////////////////////////////////////////////
            if(m_dataBuffer.atEnd()) // we read all the data there was on the file
                m_dataBuffer.resize(0); // clear everything from the file
        }
        

        "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
        ~Napoleon Bonaparte

        On a crusade to banish setIndexWidget() from the holy land of Qt

        1 Reply Last reply
        4
        • JonBJ JonB

          @kshegunov
          OK, so in a word, QDataStream::commitTransaction() fails/rolls back if there is not enough data already there at the instant it is called, period.

          BTW: so if I decide to transfer a 1GB (or more) file content as one QByteArray, and it arrives in chunks, your transaction approach will have to buffer up to 1GB of previously-received bytes, and that's presumably in memory? Hmmmm. Nobody finds that a problem?

          kshegunovK Offline
          kshegunovK Offline
          kshegunov
          Moderators
          wrote on last edited by
          #17

          @JonB said in QTcpServer with multiple persistent connections:

          so if I decide to transfer a 1GB (or more) file content as one QByteArray, and it arrives in chunks, your transaction approach will have to buffer up to 1GB of previously-received bytes, and that's presumably in memory? Hmmmm. Nobody finds that a problem?

          Not really, as you already committed a heinous crime against the system already: you read 1GB off the hard disk and send it directly to the socket. ;)
          Joking aside, what @VRonin said could work. Or you could simply split it up at the peer before sending.

          Read and abide by the Qt Code of Conduct

          JonBJ 1 Reply Last reply
          1
          • kshegunovK kshegunov

            @JonB said in QTcpServer with multiple persistent connections:

            so if I decide to transfer a 1GB (or more) file content as one QByteArray, and it arrives in chunks, your transaction approach will have to buffer up to 1GB of previously-received bytes, and that's presumably in memory? Hmmmm. Nobody finds that a problem?

            Not really, as you already committed a heinous crime against the system already: you read 1GB off the hard disk and send it directly to the socket. ;)
            Joking aside, what @VRonin said could work. Or you could simply split it up at the peer before sending.

            JonBJ Offline
            JonBJ Offline
            JonB
            wrote on last edited by
            #18

            @kshegunov
            I realise @VRonin's reply is the way to go, and have already upvoted that.

            However, your

            as you already committed a heinous crime against the system already: you read 1GB off the hard disk and send it directly to the socket. ;)

            ? My "TCP clients" in this case were the ones who read data off the disk and sent them to my server. How they did that is up to them, I have no knowledge, where's the crime? What's that got to do with your approach of having the server receive the 1GB into a memory buffer? And at least the clients, if they did read into memory, only did 1GB each. The server services 100 clients, they're all in the process of sending 1GB each, my server needs 100GB memory.... :(

            kshegunovK l3u_L 2 Replies Last reply
            0
            • JonBJ JonB

              @kshegunov
              I realise @VRonin's reply is the way to go, and have already upvoted that.

              However, your

              as you already committed a heinous crime against the system already: you read 1GB off the hard disk and send it directly to the socket. ;)

              ? My "TCP clients" in this case were the ones who read data off the disk and sent them to my server. How they did that is up to them, I have no knowledge, where's the crime? What's that got to do with your approach of having the server receive the 1GB into a memory buffer? And at least the clients, if they did read into memory, only did 1GB each. The server services 100 clients, they're all in the process of sending 1GB each, my server needs 100GB memory.... :(

              kshegunovK Offline
              kshegunovK Offline
              kshegunov
              Moderators
              wrote on last edited by
              #19

              I was just teasing. If you don't control the client, then what @VRonin wrote is the way to go.

              Read and abide by the Qt Code of Conduct

              1 Reply Last reply
              0
              • JonBJ JonB

                @kshegunov
                I realise @VRonin's reply is the way to go, and have already upvoted that.

                However, your

                as you already committed a heinous crime against the system already: you read 1GB off the hard disk and send it directly to the socket. ;)

                ? My "TCP clients" in this case were the ones who read data off the disk and sent them to my server. How they did that is up to them, I have no knowledge, where's the crime? What's that got to do with your approach of having the server receive the 1GB into a memory buffer? And at least the clients, if they did read into memory, only did 1GB each. The server services 100 clients, they're all in the process of sending 1GB each, my server needs 100GB memory.... :(

                l3u_L Offline
                l3u_L Offline
                l3u_
                wrote on last edited by
                #20

                @JonB I think what he wanted to say is that your protocol shouldn't allow sending huge packets of data in one big piece at all, and that – if you want to handle such amounts – you will have to implement it in the proper way so that everything is fine. Because if you send 1 GB to a socket using the default behavior (which will probably result in the reveiver's socket buffer filling up to 1 GB until you can read it out), you will have to read it into memory before. And you shouldn't have done that in the first place.

                JonBJ 1 Reply Last reply
                2
                • l3u_L Offline
                  l3u_L Offline
                  l3u_
                  wrote on last edited by
                  #21

                  @VRonin @kshegunov My stuff is far from finished, but at this point, I can say that this forum post and esp. the chat example helped like 100 times more than the official docs.

                  I think the chat example really should be part of the docs, as a more sophisticated example, and one for persistent connections. The fortune cookie example is nice when it comes to a very simple, one-time-use one-way connection. But somebody like me not having programmed TCP stuff at all until now simply can't figure out how to implement a bidirectional communication with multiple clients from it.

                  I'm a big step closer to being able to implement what I need thanks to your help and work, and I'm pretty sure I can learn quite a lot about TCP conenctions and handling them here :-)

                  1 Reply Last reply
                  1
                  • l3u_L l3u_

                    @JonB I think what he wanted to say is that your protocol shouldn't allow sending huge packets of data in one big piece at all, and that – if you want to handle such amounts – you will have to implement it in the proper way so that everything is fine. Because if you send 1 GB to a socket using the default behavior (which will probably result in the reveiver's socket buffer filling up to 1 GB until you can read it out), you will have to read it into memory before. And you shouldn't have done that in the first place.

                    JonBJ Offline
                    JonBJ Offline
                    JonB
                    wrote on last edited by JonB
                    #22

                    @l3u_
                    I have written TCP client/server in previous products to allow transfer of files. They seem to have worked fine for years. Neither the client nor the server read the entire file into memory to send or receive. That's all I meant.

                    Because if you send 1 GB to a socket using the default behavior (which will probably result in the reveiver's socket buffer filling up to 1 GB until you can read it out),

                    Umm, will it?? I don't think so... Pipes wouldn't do well...

                    l3u_L kshegunovK 2 Replies Last reply
                    0
                    • JonBJ JonB

                      @l3u_
                      I have written TCP client/server in previous products to allow transfer of files. They seem to have worked fine for years. Neither the client nor the server read the entire file into memory to send or receive. That's all I meant.

                      Because if you send 1 GB to a socket using the default behavior (which will probably result in the reveiver's socket buffer filling up to 1 GB until you can read it out),

                      Umm, will it?? I don't think so... Pipes wouldn't do well...

                      l3u_L Offline
                      l3u_L Offline
                      l3u_
                      wrote on last edited by l3u_
                      #23

                      @JonB I'm totally fine with everything and everybody here – I'm the one that surely has the least experience with all this here ;-) And I won't be transferring stuff that is bigger than a few hundred characters of JSON data, so the problem is surely interesting, but I don't think I have to worry about it in my case.

                      1 Reply Last reply
                      0
                      • JonBJ JonB

                        @l3u_
                        I have written TCP client/server in previous products to allow transfer of files. They seem to have worked fine for years. Neither the client nor the server read the entire file into memory to send or receive. That's all I meant.

                        Because if you send 1 GB to a socket using the default behavior (which will probably result in the reveiver's socket buffer filling up to 1 GB until you can read it out),

                        Umm, will it?? I don't think so... Pipes wouldn't do well...

                        kshegunovK Offline
                        kshegunovK Offline
                        kshegunov
                        Moderators
                        wrote on last edited by kshegunov
                        #24

                        @JonB said in QTcpServer with multiple persistent connections:

                        Umm, will it?? I don't think so... Pipes wouldn't do well...

                        Probably, yes. Qt has its own buffering on top of the socket layer, so unless you change that, by default the socket's buffer will accommodate it provided you have enough memory.

                        @l3u_ said in QTcpServer with multiple persistent connections:

                        I'm the one that surely has the least experience with all this here

                        Don't worry, give it a decade or two and you'd be the one giving the advice. ;P

                        Read and abide by the Qt Code of Conduct

                        JonBJ 1 Reply Last reply
                        2
                        • kshegunovK kshegunov

                          @JonB said in QTcpServer with multiple persistent connections:

                          Umm, will it?? I don't think so... Pipes wouldn't do well...

                          Probably, yes. Qt has its own buffering on top of the socket layer, so unless you change that, by default the socket's buffer will accommodate it provided you have enough memory.

                          @l3u_ said in QTcpServer with multiple persistent connections:

                          I'm the one that surely has the least experience with all this here

                          Don't worry, give it a decade or two and you'd be the one giving the advice. ;P

                          JonBJ Offline
                          JonBJ Offline
                          JonB
                          wrote on last edited by JonB
                          #25

                          @kshegunov said in QTcpServer with multiple persistent connections:

                          Qt has its own buffering on top of the socket layer

                          So if you then use socket "transactions" on top of the socket, I read that as doing the buffering in memory. Do you mean the transactions have to add another layer of buffering, or do they use whatever the QTcpSocket is already using?

                          kshegunovK 1 Reply Last reply
                          0
                          • JonBJ JonB

                            @kshegunov said in QTcpServer with multiple persistent connections:

                            Qt has its own buffering on top of the socket layer

                            So if you then use socket "transactions" on top of the socket, I read that as doing the buffering in memory. Do you mean the transactions have to add another layer of buffering, or do they use whatever the QTcpSocket is already using?

                            kshegunovK Offline
                            kshegunovK Offline
                            kshegunov
                            Moderators
                            wrote on last edited by
                            #26

                            @JonB said in QTcpServer with multiple persistent connections:

                            So if you then use socket "transactions" on top of the socket, I read that as doing the buffering in memory. Do you mean the transactions have to add another layer of buffering, or do they use whatever the QTcpSocket is already using?

                            They use the QAbstractSocket's buffer directly. Think of the transaction as only adding atomicity to the reading from the Qt's buffer. They do stuff similar to what @VRonin wrote about splitting your big data chunk: try to read it in the known format, if that fails, rewind the buffer's pointer. If it succeeds cut the internal buffer with what you read.

                            Read and abide by the Qt Code of Conduct

                            1 Reply Last reply
                            1
                            • D Offline
                              D Offline
                              Dick Balaska
                              wrote on last edited by Dick Balaska
                              #27

                              Sorry to jump in late here, but I've been grooving on WebSockets lately
                              (a stupid name for a good protocol). Very easy to setup and use in Qt 5. Connect a couple of signals and slots and you can reliably send and receive text and/or binary data. You can ignore the grind of TCP/IP and just mostly deal with your text.

                              kshegunovK l3u_L 2 Replies Last reply
                              1
                              • D Dick Balaska

                                Sorry to jump in late here, but I've been grooving on WebSockets lately
                                (a stupid name for a good protocol). Very easy to setup and use in Qt 5. Connect a couple of signals and slots and you can reliably send and receive text and/or binary data. You can ignore the grind of TCP/IP and just mostly deal with your text.

                                kshegunovK Offline
                                kshegunovK Offline
                                kshegunov
                                Moderators
                                wrote on last edited by
                                #28

                                That is true. There are 2 conditions to do so, however:

                                1. You want to commit to the websockets protocol, which isn't always the case.
                                2. You are willing to pull a module outside of qtbase, which is fine most of the time.

                                To expand on 1:
                                In the project I'm currently working on I have to support multiple protocols, so websockets does me no good. You may be surprised, but that case is more common than not.

                                Read and abide by the Qt Code of Conduct

                                1 Reply Last reply
                                0
                                • D Dick Balaska

                                  Sorry to jump in late here, but I've been grooving on WebSockets lately
                                  (a stupid name for a good protocol). Very easy to setup and use in Qt 5. Connect a couple of signals and slots and you can reliably send and receive text and/or binary data. You can ignore the grind of TCP/IP and just mostly deal with your text.

                                  l3u_L Offline
                                  l3u_L Offline
                                  l3u_
                                  wrote on last edited by
                                  #29

                                  @Dick-Balaska Hey, thanks for the hint with WebSockets! I never heard about this until now. At first sight, it looks promising, because it already has the methods I need for sending and receiving text (I use JSON documents for my communication).

                                  But would have using it an actual benefit for my use-case, after already having it got to work? What I did until now is (and it was surprisingly easy to implement it, as soon as someone points you towards the right way):

                                  • Writing an abstract class that cares about the data transmission and receiving, using QByteArray and QDataStream, similar to the chat example approach . It provides a sendMessage(const QString &message) function, and reads incoming messages, calling a virtual handler
                                  • Create a client derived from it that can connect to a server
                                  • Create a server that manages an object derived from it for each connection

                                  So … am I right that the only thing I could have cheaped out using WebSockets is that abstract class, because the WebSocket classes already have functions for sending and receiving text?

                                  D 1 Reply Last reply
                                  0
                                  • l3u_L l3u_

                                    @Dick-Balaska Hey, thanks for the hint with WebSockets! I never heard about this until now. At first sight, it looks promising, because it already has the methods I need for sending and receiving text (I use JSON documents for my communication).

                                    But would have using it an actual benefit for my use-case, after already having it got to work? What I did until now is (and it was surprisingly easy to implement it, as soon as someone points you towards the right way):

                                    • Writing an abstract class that cares about the data transmission and receiving, using QByteArray and QDataStream, similar to the chat example approach . It provides a sendMessage(const QString &message) function, and reads incoming messages, calling a virtual handler
                                    • Create a client derived from it that can connect to a server
                                    • Create a server that manages an object derived from it for each connection

                                    So … am I right that the only thing I could have cheaped out using WebSockets is that abstract class, because the WebSocket classes already have functions for sending and receiving text?

                                    D Offline
                                    D Offline
                                    Dick Balaska
                                    wrote on last edited by
                                    #30

                                    @l3u_ If you have already hardened [1] your QTcpSocket implementation, then there's no reason to switch, except for maybe ease of SSL support.
                                    For new work, these days I try to use WebSockets. I, too, use JSON. Each asynchronous message is just a command token followed by a JSON string.

                                    [1] You handle message fragmentation and reconnects, right?

                                    l3u_L 1 Reply Last reply
                                    0
                                    • D Dick Balaska

                                      @l3u_ If you have already hardened [1] your QTcpSocket implementation, then there's no reason to switch, except for maybe ease of SSL support.
                                      For new work, these days I try to use WebSockets. I, too, use JSON. Each asynchronous message is just a command token followed by a JSON string.

                                      [1] You handle message fragmentation and reconnects, right?

                                      l3u_L Offline
                                      l3u_L Offline
                                      l3u_
                                      wrote on last edited by
                                      #31

                                      @Dick-Balaska said in QTcpServer with multiple persistent connections:

                                      [1] You handle message fragmentation and reconnects, right?

                                      Of course I don't – or at least, I don't know – or I'm not sure ;-)

                                      Would you please explain what you mean? If a "reconnect" is loss of a client connection followed by a new connect, I handle it (the client is removed from the server's client list as soon as it disconnects and is simply added like a new one when it reconnects).

                                      If "message fragmentation" is that "you can't expect all data to arrive in one piece", I think this is already handled by the chat example (cf. ChatClient::onReadyRead()).

                                      I don't need encryption and such, the protocol will only be used in a closed LAN consisting of two or three computers, the data itself is not confidential, and I also don't need to protect against manipulation etc. (somebody trying this would shoot himself in the foot as the program probably wouldn't work as expected in this case).

                                      D 1 Reply Last reply
                                      1
                                      • l3u_L l3u_

                                        @Dick-Balaska said in QTcpServer with multiple persistent connections:

                                        [1] You handle message fragmentation and reconnects, right?

                                        Of course I don't – or at least, I don't know – or I'm not sure ;-)

                                        Would you please explain what you mean? If a "reconnect" is loss of a client connection followed by a new connect, I handle it (the client is removed from the server's client list as soon as it disconnects and is simply added like a new one when it reconnects).

                                        If "message fragmentation" is that "you can't expect all data to arrive in one piece", I think this is already handled by the chat example (cf. ChatClient::onReadyRead()).

                                        I don't need encryption and such, the protocol will only be used in a closed LAN consisting of two or three computers, the data itself is not confidential, and I also don't need to protect against manipulation etc. (somebody trying this would shoot himself in the foot as the program probably wouldn't work as expected in this case).

                                        D Offline
                                        D Offline
                                        Dick Balaska
                                        wrote on last edited by
                                        #32

                                        @l3u_ I see class ChatClient referenced in two examples (linux Qt 5.11.2), bluetooth, which I don't think you're doing, and WebChannel, which actually sits on top of WebSockets. So, I'm not sure what your base is.

                                        WebSockets guarantees you get a whole message at a time. A regular socket (QTcpSocket) you just know you have x bytes available and it's up to you to frame them in a message. (Like http knows that \n\n is the end of the request headers).
                                        Clearly you're well beyond that.
                                        If you're unsure about message fragmentation, make a class with a >2k byte object and see if you get it in one message. (hardwired lan TCP is 1536 bytes per packet. Wifi is about 400 bytes per packet.)

                                        kshegunovK 1 Reply Last reply
                                        0
                                        • D Dick Balaska

                                          @l3u_ I see class ChatClient referenced in two examples (linux Qt 5.11.2), bluetooth, which I don't think you're doing, and WebChannel, which actually sits on top of WebSockets. So, I'm not sure what your base is.

                                          WebSockets guarantees you get a whole message at a time. A regular socket (QTcpSocket) you just know you have x bytes available and it's up to you to frame them in a message. (Like http knows that \n\n is the end of the request headers).
                                          Clearly you're well beyond that.
                                          If you're unsure about message fragmentation, make a class with a >2k byte object and see if you get it in one message. (hardwired lan TCP is 1536 bytes per packet. Wifi is about 400 bytes per packet.)

                                          kshegunovK Offline
                                          kshegunovK Offline
                                          kshegunov
                                          Moderators
                                          wrote on last edited by
                                          #33

                                          @Dick-Balaska said in QTcpServer with multiple persistent connections:

                                          I see class ChatClient referenced in two examples (linux Qt 5.11.2), bluetooth, which I don't think you're doing, and WebChannel, which actually sits on top of WebSockets. So, I'm not sure what your base is.

                                          Scroll up. The OP is using as a base the WIP example from the wiki I sourced in my first post.

                                          @l3u_ said in QTcpServer with multiple persistent connections:

                                          If "message fragmentation" is that "you can't expect all data to arrive in one piece", I think this is already handled by the chat example (cf. ChatClient::onReadyRead()).

                                          Yes, this is correct.

                                          Read and abide by the Qt Code of Conduct

                                          D 1 Reply Last reply
                                          1

                                          • Login

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • Users
                                          • Groups
                                          • Search
                                          • Get Qt Extensions
                                          • Unsolved