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. QTcpSocket / QTcpServer, two way communication
Forum Updated to NodeBB v4.3 + New Features

QTcpSocket / QTcpServer, two way communication

Scheduled Pinned Locked Moved Unsolved General and Desktop
23 Posts 3 Posters 3.9k Views 2 Watching
  • 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.
  • SPlattenS Offline
    SPlattenS Offline
    SPlatten
    wrote on last edited by SPlatten
    #10

    The only purpose of this application is to act as a gateway / server between another application and the various modules it creates, I sub-classed QTcpServer because the main class and purpose is to be a server, I see no problem in doing this and its cleaner.

    I agree with you on naming slots with a prefix of 'on' and this is exactly what I usually do.

    Kind Regards,
    Sy

    KroMignonK 1 Reply Last reply
    0
    • SPlattenS SPlatten

      The only purpose of this application is to act as a gateway / server between another application and the various modules it creates, I sub-classed QTcpServer because the main class and purpose is to be a server, I see no problem in doing this and its cleaner.

      I agree with you on naming slots with a prefix of 'on' and this is exactly what I usually do.

      KroMignonK Offline
      KroMignonK Offline
      KroMignon
      wrote on last edited by KroMignon
      #11

      @SPlatten said in QTcpSocket / QTcpServer, two way communication:

      purpose is to be a server, I see no problem in doing this and its cleaner.

      But why did you reimplement incomingConnection() ?
      Don't understand my wrong, it is not a judgement in any form, I only wonder why you have to do it.

      It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

      SPlattenS 1 Reply Last reply
      0
      • KroMignonK KroMignon

        @SPlatten said in QTcpSocket / QTcpServer, two way communication:

        purpose is to be a server, I see no problem in doing this and its cleaner.

        But why did you reimplement incomingConnection() ?
        Don't understand my wrong, it is not a judgement in any form, I only wonder why you have to do it.

        SPlattenS Offline
        SPlattenS Offline
        SPlatten
        wrote on last edited by
        #12

        @KroMignon , My incomingConnection:

        void clsSocketServer::incomingConnection(qintptr sfd) {
            clsSocketClient* pClient = new clsSocketClient(this);
            pClient->setSocketDescriptor(sfd);
            addPendingConnection(pClient);   
        }
        

        This part of the application is working ok, in that an external application can send messages to the server, but its sending messages from the server to the external application that is failing...all except the Acknowledge message which does make to the external application.

        Kind Regards,
        Sy

        KroMignonK 1 Reply Last reply
        0
        • SPlattenS SPlatten

          @KroMignon , My incomingConnection:

          void clsSocketServer::incomingConnection(qintptr sfd) {
              clsSocketClient* pClient = new clsSocketClient(this);
              pClient->setSocketDescriptor(sfd);
              addPendingConnection(pClient);   
          }
          

          This part of the application is working ok, in that an external application can send messages to the server, but its sending messages from the server to the external application that is failing...all except the Acknowledge message which does make to the external application.

          KroMignonK Offline
          KroMignonK Offline
          KroMignon
          wrote on last edited by KroMignon
          #13

          @SPlatten said in QTcpSocket / QTcpServer, two way communication:

          its sending messages from the server to the external application that is failing...all except the Acknowledge message which does make to the external application.

          Just be sure we are talking about the same issue:
          You have a TCP client which is connected to the TCP server, the connected client has an instance of clsSocketClient (which seems to be a subclass of QTcpSocket). Let's call the instance mClient.
          When you do mClient.write(<something>), you've got an error.

          Is that your problem?

          It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

          SPlattenS 1 Reply Last reply
          0
          • KroMignonK KroMignon

            @SPlatten said in QTcpSocket / QTcpServer, two way communication:

            its sending messages from the server to the external application that is failing...all except the Acknowledge message which does make to the external application.

            Just be sure we are talking about the same issue:
            You have a TCP client which is connected to the TCP server, the connected client has an instance of clsSocketClient (which seems to be a subclass of QTcpSocket). Let's call the instance mClient.
            When you do mClient.write(<something>), you've got an error.

            Is that your problem?

            SPlattenS Offline
            SPlattenS Offline
            SPlatten
            wrote on last edited by SPlatten
            #14

            @KroMignon , there is no error sending data from the client to the server application, it regularly sends a message, a heartbeat message, which the server responds with an acknowledge. This acknowledge is also sent from the server with no error.

            However if the server attempts to send any other message to the client, this fails and is not written, the return is -1.

            Kind Regards,
            Sy

            KroMignonK 1 Reply Last reply
            0
            • SPlattenS SPlatten

              @KroMignon , there is no error sending data from the client to the server application, it regularly sends a message, a heartbeat message, which the server responds with an acknowledge. This acknowledge is also sent from the server with no error.

              However if the server attempts to send any other message to the client, this fails and is not written, the return is -1.

              KroMignonK Offline
              KroMignonK Offline
              KroMignon
              wrote on last edited by
              #15

              @SPlatten said in QTcpSocket / QTcpServer, two way communication:

              However if the server attempts to send any other message to the client, this fails and is not written, the return is -1.

              I don't understand this, what do you mean with "server attempts to send to client"?
              The server TCP socket can not send/receive anything, it can only accept/reject connection requests, which are transferred to a new TCP socket. This is TCP basics, or did I misunderstood something?

              Can you be more explicit or show a code extract?

              It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

              SPlattenS 1 Reply Last reply
              0
              • KroMignonK KroMignon

                @SPlatten said in QTcpSocket / QTcpServer, two way communication:

                However if the server attempts to send any other message to the client, this fails and is not written, the return is -1.

                I don't understand this, what do you mean with "server attempts to send to client"?
                The server TCP socket can not send/receive anything, it can only accept/reject connection requests, which are transferred to a new TCP socket. This is TCP basics, or did I misunderstood something?

                Can you be more explicit or show a code extract?

                SPlattenS Offline
                SPlattenS Offline
                SPlatten
                wrote on last edited by
                #16

                @KroMignon , the intention is for the server to be able to send messages to the client. However when I've tried to do this is always fails, yet a response to a message received by the server is always successful..

                Kind Regards,
                Sy

                1 Reply Last reply
                0
                • SGaistS Offline
                  SGaistS Offline
                  SGaist
                  Lifetime Qt Champion
                  wrote on last edited by
                  #17

                  Not knowing your code base it's difficult to answer since we do not know what happens client side and we do not know how you handle the sending of message back to the client.

                  One thing however is that it looks like you are making things more complicated than necessary. From your description, you seem to need a QTcpServer to get the connections and then a list of QTcpSocket for the exchange of messages. So I fail to see the need to subclass both of them in order to implement your proxy.

                  Interested in AI ? www.idiap.ch
                  Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                  SPlattenS 1 Reply Last reply
                  1
                  • SGaistS SGaist

                    Not knowing your code base it's difficult to answer since we do not know what happens client side and we do not know how you handle the sending of message back to the client.

                    One thing however is that it looks like you are making things more complicated than necessary. From your description, you seem to need a QTcpServer to get the connections and then a list of QTcpSocket for the exchange of messages. So I fail to see the need to subclass both of them in order to implement your proxy.

                    SPlattenS Offline
                    SPlattenS Offline
                    SPlatten
                    wrote on last edited by
                    #18

                    @SGaist , subclass or not subclass, the implementation would be the same?

                    The clients all send the server regular heartbeats, if a client does not receive an ack in response to the heartbeat then it can determine that the server is no longer running and self terminate.

                    From time to time the server will issue commands to the clients, its these that do not work.

                    In trying to fix this I've managed to break everything so once I get it back up I will publish some source.

                    Kind Regards,
                    Sy

                    KroMignonK 1 Reply Last reply
                    0
                    • SGaistS Offline
                      SGaistS Offline
                      SGaist
                      Lifetime Qt Champion
                      wrote on last edited by
                      #19

                      @SPlatten said in QTcpSocket / QTcpServer, two way communication:

                      @SGaist , subclass or not subclass, the implementation would be the same?

                      Not necessarily, it depends on what your code does.

                      Interested in AI ? www.idiap.ch
                      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                      1 Reply Last reply
                      0
                      • SPlattenS SPlatten

                        @SGaist , subclass or not subclass, the implementation would be the same?

                        The clients all send the server regular heartbeats, if a client does not receive an ack in response to the heartbeat then it can determine that the server is no longer running and self terminate.

                        From time to time the server will issue commands to the clients, its these that do not work.

                        In trying to fix this I've managed to break everything so once I get it back up I will publish some source.

                        KroMignonK Offline
                        KroMignonK Offline
                        KroMignon
                        wrote on last edited by KroMignon
                        #20

                        @SPlatten said in QTcpSocket / QTcpServer, two way communication:

                        From time to time the server will issue commands to the clients, its these that do not work.
                        In trying to fix this I've managed to break everything so once I get it back up I will publish some source.

                        It looks to me as you want to reimplement TCP KeepAlive feature.
                        Why do not simply activate KeepAlive option on TCP socket?

                        But perhaps I don't understand very well your explanation.
                        When you are talking about "server" and "client" do you mean the application or the socket?

                        It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

                        1 Reply Last reply
                        0
                        • SPlattenS Offline
                          SPlattenS Offline
                          SPlatten
                          wrote on last edited by
                          #21

                          @KroMignon , by server I mean the application using QTcpServer that is in effect the master because it is the application that starts the other processes, listens for incoming messages and issues commands to the other processes.

                          The clients use QTcpSocket to connect to the server application. If the server goes away then the clients will self terminate. I don't know about the KeepAlive feature so I will read up, but basically the heartbeat is an alternative to pinging the server to see if it is active and responding. Can I self terminate if the server doesn't respond using the KeepAlive?

                          Kind Regards,
                          Sy

                          KroMignonK 1 Reply Last reply
                          0
                          • SPlattenS SPlatten

                            @KroMignon , by server I mean the application using QTcpServer that is in effect the master because it is the application that starts the other processes, listens for incoming messages and issues commands to the other processes.

                            The clients use QTcpSocket to connect to the server application. If the server goes away then the clients will self terminate. I don't know about the KeepAlive feature so I will read up, but basically the heartbeat is an alternative to pinging the server to see if it is active and responding. Can I self terminate if the server doesn't respond using the KeepAlive?

                            KroMignonK Offline
                            KroMignonK Offline
                            KroMignon
                            wrote on last edited by KroMignon
                            #22

                            @SPlatten said in QTcpSocket / QTcpServer, two way communication:

                            Can I self terminate if the server doesn't respond using the KeepAlive?

                            TCP KeepAlive feature, send "non data" packet between two endpoints to check if counterpart is still present/reachable. If not, the connection is closed (cf. https://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html).

                            To enable KeepAlive: socket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);

                            But, there are always some backdrawn. With Qt, you can only switch on the KeepAlive feature for the socket (must be done when socket is connected, not before!).
                            According to your OS, you also have to setup the KeepAlive parameters:

                            • IDLE interval before starting KeepAlive
                            • how many KeepAlive retries before deconnection
                            • interval between each KeepAlive

                            For example for Linux (maybe Unix?) system, the TCP settings can be found on /proc/sys/net/ipv4:

                            • tcp_keepalive_time: interval between the last data packet sent and the first keepalive probe in seconds.
                            • tcp_keepalive_intvl: interval between subsequent keepalive probes in seconds.
                            • tcp_keepalive_probes: number of probes that are sent and unacknowledged before the client considers the connection broken and notifies the application layer

                            It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

                            1 Reply Last reply
                            3
                            • SPlattenS Offline
                              SPlattenS Offline
                              SPlatten
                              wrote on last edited by SPlatten
                              #23

                              Whats the live cycle of a connection with QTcpSocket?

                              My client connects to the application which is listening, here is the client connection code:

                              setSocketOption(QAbstractSocket::LowDelayOption, 1);
                              //Get the I/P address
                              QList<QHostAddress> lstAddresses = QNetworkInterface::allAddresses();
                              QString strIP;
                              for( int i=0; i<lstAddresses.size(); i++ ) {
                                  if ( lstAddresses[i] != QHostAddress::LocalHost
                                    && lstAddresses[i].toIPv4Address() ) {
                                      strIP = lstAddresses[i].toString();
                                      break;
                                  }
                              }
                              if ( strIP.isEmpty() == true ) {
                                  strIP = QHostAddress(QHostAddress::LocalHost).toString();
                              }
                              //Connect to the Application
                              qdbg() << "Connecting to: " << strIP << ":" << muint16XMLMPAMport;
                              connectToHost(strIP, muint16XMLMPAMport);
                              

                              The port is 8124. This does connect to the server and sends a message with:

                              void clsSocketClient::sendJSON(const QJsonObject& crobjJSON) {
                                  if ( isOpen() != true ) {
                                      return;
                                  }
                                  //Associate this TCP socket with the output data stream
                                  QByteArray arybytMsg;
                                  QDataStream dsOut(&arybytMsg, QIODevice::WriteOnly);
                                  dsOut.setVersion(clsJSON::mscintQtVersion);
                                  //Send message to data stream
                                  dsOut << QJsonDocument(crobjJSON).toJson(QJsonDocument::Compact);
                              
                                  //Write message
                              #if defined(DEBUG_SOCKETS)
                                  qint64 int64Written =
                              #endif
                                  write(arybytMsg);    
                              #if defined(DEBUG_SOCKETS)    
                                  QJsonDocument objDoc(crobjJSON);
                                  qdbg() << "clsSocketClient::sendJSON"
                                         << "[" << int64Written << "]:"
                                         << QString(objDoc.toJson(QJsonDocument::Compact));
                              #endif
                              }
                              

                              This works and I can see that int64Written is > 0 in the Application Output. The server application receives this message and sends and Ack:

                              bool blnDecodeHeartbeat(const QJsonObject& crobjJSON) {
                                  QJsonObject::const_iterator citrFound = crobjJSON.find(clsJSON::mscszModule);
                              
                                  if ( citrFound == crobjJSON.end() ) {
                                      return false;
                                  }
                                  QString strModuleName = citrFound.value().toString();
                                  clsModule* pModule = clsModule::pGetModule(strModuleName);
                              
                                  if ( pModule == nullptr ) {
                                      return false;
                                  }
                                  pModule->updateHearbeat();
                                  //Send acknowledge back to module
                                  QJsonObject objJSON;
                                  objJSON.insert(clsJSON::mscszModule, strModuleName);
                                  objJSON.insert(clsJSON::mscszMsgType, clsJSON::mscszAck);
                                  //Cast the socket to the required type
                                  emit pModule->sendJSON(objJSON);
                                  return true;
                              }
                              

                              This decode is called the instance the message arrives from the client and the sending of the Ack message is always successful. The server later tries to send a message to the client which is not the result of receiving a message:

                              void clsScriptHelper::notify(const QJsonObject& crobjModule
                                                          ,QJsonObject objCmds) {
                                  QJsonObject::const_iterator citrFound = crobjModule.find(clsJSON::mscszModule);
                                  QString strModuleName;
                                  clsModule* pModule;
                              
                                  if ( citrFound == crobjModule.end() ) {
                                      return;
                                  }
                                  strModuleName = citrFound.value().toString();
                                  //Make sure the module is set in the message
                                  objCmds.insert(clsJSON::mscszModule, strModuleName);
                                  //Set command type
                                  objCmds.insert(clsJSON::mscszMsgType, clsJSON::mscszCmdNotify);
                                  //Look up the socket for the module
                                  pModule = clsModule::pGetModule(strModuleName);
                              
                                  if ( pModule == nullptr || pModule->blnTxAllowed() != true ) {
                                      clsModule::sendLater(strModuleName, objCmds);
                                      return;
                                  }
                                  //Convert object into byte array for transmission
                                  emit pModule->sendJSON(objCmds);
                              }
                              

                              The code to send Later:

                              void clsModule::sendLater(const QString& crstrModule, const QJsonObject& crobjJSON) {
                                  mpSendLater::iterator itrList = clsModule::msmpSendLaterLst.find(crstrModule);
                                  QJsonObject* pobjJSON;
                              
                                  if ( itrList != clsModule::msmpSendLaterLst.end() ) {
                                      pobjJSON = itrList->second;
                                  } else {
                                      pobjJSON = new QJsonObject();
                              
                                      if ( pobjJSON != nullptr ) {
                                          clsModule::msmpSendLaterLst.insert(std::make_pair(crstrModule, pobjJSON));
                                      }
                                  }
                                  if ( pobjJSON != nullptr ) {
                                      *pobjJSON = crobjJSON;
                              #if defined(DEBUG_SOCKETS)
                                      QString strExpoded(clsJSON::strExplodeJSON(*pobjJSON, 0));
                                      qdbg() << "clsModule::sendLater: " << strExpoded.toLatin1().data();
                              #endif
                                  }
                              }
                              

                              The purpose of this function is that if the client is not connected or not ready then it inserts the message into a map that is supposed to be transmitted when the client next connects.

                              When the client is connected the waiting messages are sent using the clsSocketClient::sendJSON as posted above, and this fails 100% of the time. Why?

                              Its as if the client isn't ready to receive a message. Typical output in Application Output:

                              D00000000000000000028T000000000915:clsJSON::commonDecode [50]: {"module":"mdFileIO","msgType":"init","port":8124}
                              W00000000000000000029T000000001334:QProcess::setProgram: Process is already running
                              D00000000000000000030T000000001334:Process: mdFileIO started, PID: 1046
                              D00000000000000000031T000000002816:clsJSON::commonDecode [49]: {"PID":"1046","module":"mdFileIO","msgType":"hb"}
                              D00000000000000000032T000000002816:clsSocketClient::sendJSON[41]:{"module":"mdFileIO","msgType":"ack"}
                              D00000000000000000033T000000002816:clsSocketClient::onBytesWritten:41
                              D00000000000000000034T000000004718:clsJSON::commonDecode [49]: {"PID":"1046","module":"mdFileIO","msgType":"hb"}
                              D00000000000000000035T000000004718:clsSocketClient::sendJSON[41]:{"module":"mdFileIO","msgType":"ack"}
                              D00000000000000000036T000000004718:clsSocketClient::onBytesWritten:41
                              

                              Kind Regards,
                              Sy

                              1 Reply Last reply
                              0

                              • Login

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