Hello,

I have a console application that talks to another (main) application using udp sockets and waits for a reply. I wrote the initial code (which didn't have these problems) in Qt4.8 but I am now on Qt5.5 and it is not working as it was.
I am getting 3 errors:
1. "QObject::killTimer: Timers cannot be stopped from another thread" and QObject::startTimer: Timers cannot be stopped from another thread"
2. QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread
(this can be 'corrected' by the line : udpReceiverThread->moveToThread(udpReceiverThread); not sure if it is the right thing to do though based on what i have read
3. replyNotReceived SLOT is not being called (replyTimer).


main.cpp starts ArcConsoleInput and ArcConsoleInput starts the UdpThread. There are 2 timers in the code

1. timeoutTimer - if the user has not typed in any commands in 1 minute the ArcConsoleApp quits
2. replyTimer - the thread waits 5 seconds for a reply, if no reply received (e.g. main app not running) then message goes to std::cout.

How do I get rid of error #1 and get the replyNotReceived SLOT to run..

I have being trying for a few days to get this working using various qt websites, pages, forums but not having any luck.

Thank you for your help


ArcConsoleInput.h

Qt Code:
  1. private:
  2. /*! Timer for when there has been no user interaction for userTimeout seconds */
  3. QTimer* timeoutTimer;
  4.  
  5. /*! A SocketNotifier to read from Standard Input */
  6. QSocketNotifier* notifier;
  7.  
  8. /*! A file to read standard input from */
  9. QFile* stdin;
  10.  
  11. /*! A UdpThread that will receive replies from the ARC */
  12. UdpThread* udpReceiverThread;
  13.  
  14. /*! A UDP socket to send requests to the ARC software */
  15. QUdpSocket *udpSocketArcSender;
To copy to clipboard, switch view to plain text mode 

ArcConsoleInput.cpp
Qt Code:
  1. void ArcConsoleInput::networkSetup()
  2. {
  3. //create a sender UDP socket
  4. udpSocketArcSender = new QUdpSocket(this);
  5.  
  6. //create a thread for the a udp receiver sockets
  7. udpReceiverThread = new UdpThread();
  8. udpReceiverThread->start();
  9. //to stop error:QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread
  10. udpReceiverThread->moveToThread(udpReceiverThread);
  11.  
  12. //Create a SocketNotifier to read from Standard Input
  13. stdin = new QFile();
  14. stdin->open(0, QIODevice::ReadOnly);
  15. notifier = new QSocketNotifier(0, QSocketNotifier::Read);
  16. connect(notifier, SIGNAL(activated(int)), this, SLOT(readUserLine()));
  17.  
  18. //Create a timer for when there has been no user interaction for userTimeout seconds
  19. timeoutTimer = new QTimer(0);
  20. connect(timeoutTimer, SIGNAL(timeout()), this, SLOT(timeExpired()));
  21. timeoutTimer->setInterval(userTimeout);
  22. timeoutTimer->start();
  23. }
  24.  
  25. /*****************************************************************
  26.  * Name: sendUserInput
  27.  * Description: Send the line from stdin to the socket for sending to ARC
  28.  ******************************************************************/
  29. void ArcConsoleInput::sendUserInput(QString line)
  30. {
  31. QByteArray datagram = line.toUtf8();
  32. udpSocketArcSender->writeDatagram(datagram.data(), datagram.size(), QHostAddress::LocalHost, quint16(port));
  33. }
  34.  
  35. /*****************************************************************
  36.  * Name: readLine
  37.  * Description: Read the line from stdin and process
  38.  ******************************************************************/
  39. void ArcConsoleInput::readUserLine()
  40. {
  41. QString line;
  42. char buf[1024];
  43. QRegExp rx("[a-z]*[0-9]{1,2}$");
  44.  
  45. stdin->readLine(buf, sizeof(buf));
  46. line = QString::fromStdString(buf).trimmed().toLower();
  47.  
  48. if(line != NULL)
  49. {
  50. std::cout << "\n" << std::flush;
  51.  
  52. if((QString::compare(line, "quit", Qt::CaseInsensitive) == 0) ||
  53. (QString::compare(line, "exit", Qt::CaseInsensitive) == 0))
  54. {
  55. qDebug("Exiting Console Application");
  56. exit(1);
  57. }
  58. else if (QString::compare(line, "status", Qt::CaseInsensitive) == 0)
  59. {
  60. udpReceiverThread->setReplyReceived(false);
  61. sendUserInput(line);
  62. }
  63. //more stuff here
  64. else
  65. {
  66. qDebug() << "Unknown console input! " << line << "\nType help for assistance";
  67. std::cout << "\n>" << std::flush;
  68. }
  69.  
  70. restartTimer();
  71.  
  72. }
  73. else //empty line - user interaction has occurred
  74. {
  75. std::cout << ">" << std::flush;
  76. restartTimer();
  77. }
  78. }
  79.  
  80. /*****************************************************************
  81.  * Name: restartTimer
  82.  * Description: User interaction has occurred restart the timer
  83.  ******************************************************************/
  84. void ArcConsoleInput::restartTimer()
  85. {
  86. if(timeoutTimer->isActive() == true)
  87. timeoutTimer->stop();
  88.  
  89. if(timeoutTimer->isActive() == false)
  90. timeoutTimer->start();
  91. }
  92.  
  93. /*****************************************************************
  94.  * Name: timeExpired
  95.  * Description: ArcConsoleApp will automatically close if no user interaction for "userTimeout" seconds
  96.  ******************************************************************/
  97. void ArcConsoleInput::timeExpired()
  98. {
  99. qDebug("\nTimeout: ArcConsoleApp is closing!");
  100. delete udpSocketArcSender;
  101. }
To copy to clipboard, switch view to plain text mode 


UdpThread.h
Qt Code:
  1. class UdpThread : public QThread
  2. {
  3. Q_OBJECT
  4.  
  5. public:
  6.  
  7. /*! Constructor */
  8. UdpThread();
  9.  
  10. /*! Destructor */
  11. ~UdpThread();
  12.  
  13. /*! Wait for pending datagrams from the socket to read */
  14. void run() override;
  15.  
  16. /*! set the value of the reply */
  17. void setReplyReceived(bool r);
  18.  
  19. /*! get the value of replyReceived */
  20. bool getReplyReceived();
  21.  
  22. private slots:
  23.  
  24. /*! Read all pending datagrams from the socket and print to screen */
  25. void readPendingDatagrams();
  26.  
  27. /*! Slot for when a reply from ARC has not been received for replyTimeout */
  28. void replyNotReceived();
  29.  
  30. private:
  31. /*! 5 second timer for the receipt of a reply from ARC */
  32. QTimer *replyTimer;
  33.  
  34. /*! UDP Socket to receive replies from the ARC */
  35. QUdpSocket *udpSocketReceiver;
  36.  
  37. /*! Has a reply been received */
  38. bool replyReceived;
  39.  
  40. Q_Log *logging;
  41. };
To copy to clipboard, switch view to plain text mode 


UdpThread.cpp
Qt Code:
  1. #include <signal.h>
  2. #include <iostream>
  3. #include <QtNetwork>
  4. #include <QString>
  5.  
  6. #include "UdpThread.h"
  7.  
  8. static const int replyTimeout = 1 * 5000; //5 seconds
  9. #define RECEIVING_PORT 34568
  10.  
  11. /*****************************************************************
  12. * Name: UdpThread
  13. * Description: Constructor.
  14. ******************************************************************/
  15. UdpThread::UdpThread() : replyTimer(), udpSocketReceiver(), replyReceived(false), logging()
  16. {
  17. udpSocketReceiver = new QUdpSocket(this);
  18. udpSocketReceiver->bind(QHostAddress::LocalHost, RECEIVING_PORT);
  19.  
  20.  
  21. replyTimer = new QTimer(0);
  22. connect(replyTimer, SIGNAL(timeout()), this, SLOT(replyNotReceived()));
  23. replyTimer->setInterval(replyTimeout);
  24. }
  25.  
  26. /*****************************************************************
  27. * Name: ~UdpThread
  28. * Description: Destructor
  29. ******************************************************************/
  30. UdpThread::~UdpThread()
  31. {
  32. delete udpSocketReceiver;
  33. setTerminationEnabled(true);
  34. qDebug("Closing UDP Receiver Thread in ARC Console App");
  35. }
  36.  
  37. /*****************************************************************
  38. * Name: run
  39. * Description: Wait for pending datagrams from the socket to read
  40. ******************************************************************/
  41. [[noreturn]] void UdpThread::run(void)
  42. {
  43. QString msg;
  44.  
  45. for(;;)
  46. {
  47. if(udpSocketReceiver->hasPendingDatagrams())
  48. {
  49. readPendingDatagrams();
  50. }
  51. }
  52. }
  53.  
  54. /*****************************************************************
  55. * Name: readPendingDatagrams
  56. * Description: Read all pending datagrams from the socket and print to screen
  57. ******************************************************************/
  58. void UdpThread::readPendingDatagrams()
  59. {
  60. QString msg;
  61.  
  62. while (udpSocketReceiver->hasPendingDatagrams())
  63. {
  64. QByteArray datagram;
  65. datagram.resize(static_cast<int>(udpSocketReceiver->pendingDatagramSize()));
  66. QHostAddress senderAddr = QHostAddress::LocalHost;
  67. quint16 senderPort = RECEIVING_PORT;
  68.  
  69. udpSocketReceiver->readDatagram(datagram.data(), datagram.size(),
  70. &senderAddr, &senderPort);
  71.  
  72. //qDebug("%s", datagram.data());
  73. qDebug() << datagram.data();
  74. msleep(50); //to get all datagrams in the same request together without exiting while loop
  75.  
  76. if(replyTimer->isActive() == true)
  77. replyTimer->stop();
  78.  
  79. setReplyReceived(true);
  80. }
  81. std::cout << "\n>" << std::flush;
  82. }
  83. /*****************************************************************
  84. * Name: setReplyReceived
  85. * Description: set the value of the reply
  86. ******************************************************************/
  87. void UdpThread::setReplyReceived(bool r)
  88. {
  89. replyReceived = r;
  90.  
  91. if(r == false) {
  92. replyTimer->start();
  93. }
  94. }
  95.  
  96. /*****************************************************************
  97. * Name: getReplyReceived
  98. * Description: get the value of replyReceived
  99. ******************************************************************/
  100. bool UdpThread::getReplyReceived(void)
  101. {
  102. return replyReceived;
  103. }
  104.  
  105. /*****************************************************************
  106. * Name: replyNotReceived
  107. * Description: Slot for when a reply from ARC has not been received for replyTimeout
  108. ******************************************************************/
  109. void UdpThread::replyNotReceived()
  110. {
  111. std::cout << "No reply received, try again or check that ARC is running!\n\n>" << std::flush;
  112.  
  113. if(replyTimer->isActive() == true)
  114. replyTimer->stop();
  115. }
To copy to clipboard, switch view to plain text mode