February 23, 2011

javid javid
Lab Rat
6 posts

Can’t receive tcp message when popping up a modal dialog?

 

My goal is to receive the tcp message from the server, and execute some jobs.
But it’s hard to copy all code to here…

In short, I refer to the Qt example “Fortune client”, make it connect to server, receive message, etc.
Just like the example :

  1. connect(tcpSocket, SIGNAL(readyRead() ), this, SLOT(slot_myReadMsg()) );

And the slot_myReadMsg() :

  1. void QxSpySocket::slot_myReadMsg(){
  2.  QDataStream in(connection);
  3.  in.setVersion(QDataStream::Qt_4_0);
  4.  if (blockSize == 0) {
  5.   if (connection->bytesAvailable() < (int)sizeof(quint16))
  6.    return;
  7.   in >> blockSize;
  8.  }
  9.  if (connection->bytesAvailable() < blockSize)
  10.   return;
  11.  QString msg;
  12.  in >> msg;
  13.  blockSize = 0;
  14.  QxSpy::getInstance()->slot_parseTCPMessage(msg);
  15. }

It works fine for a while.
But recently, I found a weird problem of Qt.

When I open a modal dialog, then the server sends message to client, readyRead() never be triggered.
Why? Does it mean that when I open a modal dialog, qt will be blocked at the dialog until I click “OK” or “Cancel”?

After that I’ve tried to create two socket, one for write, one for read.
Make one of them to listen in another thread (see Example “Blocking Fortune Client”)
The thread just like this :

  1. void QxSocketThread::run(){
  2.  const int Timeout = 60 * 1000;
  3.  
  4.  while(1){
  5.   QString command = "";
  6.   while (_socket->getSocket()->bytesAvailable() < (int)sizeof(quint16)) {
  7.    if (!_socket->getSocket()->waitForReadyRead(Timeout)) {
  8.     //emit error(_socket->getSocket()->error(), _socket->getSocket()->errorString());
  9.     return;
  10.    }
  11.   }
  12.   quint16 blockSize;
  13.   QDataStream in(_socket->getSocket());
  14.   in.setVersion(QDataStream::Qt_4_0);
  15.   in >> blockSize;
  16.  
  17.   while (_socket->getSocket()->bytesAvailable() < blockSize) {
  18.    if (!_socket->getSocket()->waitForReadyRead(Timeout)) {
  19.     //emit error(_socket->getSocket()->error(), _socket->getSocket()->errorString());
  20.     return;
  21.    }
  22.   }
  23.   in >> command;
  24.  
  25.   MyCommandParser::getInstance()->parse(command);
  26.   msleep(50);
  27.  }
  28. }

In VC, it will output the warning : “QSocketNotifier: socket notifiers cannot be disabled from another thread”
I’ve read several thread about it, but none of them can tackle it.

Anyone can help me??? Plz…
My opinion, I like the signal-slot approach rather than the blocking approach.

10 replies

February 23, 2011

Volker Volker
Ant Farmer
5428 posts

While a message box is open with exec, it will run its own event loop. During this time, the main event loop is not run and therefore the events and signals are not processed.

February 23, 2011

peppe peppe
Ant Farmer
1029 posts

When I open a modal dialog, then the server sends message to client, readyRead() never be triggered.
Why? Does it mean that when I open a modal dialog, qt will be blocked at the dialog until I click “OK” or “Cancel”?

No: opening a dialog with exec() will reenter the event loop (with all the pros/cons).

http://developer.qt.nokia.com/wiki/Threads_Events_QObjects

 Signature 

Software Engineer
KDAB (UK) Ltd., a KDAB Group company

February 24, 2011

javid javid
Lab Rat
6 posts

Thanks to Volker and peppe.

So, does it means I never could open a dialog with exec() and listen the socket message??
is there any possible implementation?

It’s a classical web client program. User can manipulate and the program will communicate with server in background.
But I just open a modal dialog (QFileDialog) to ask user to select a file :

  1. QString fileName = QFileDialog::getOpenFileName(label, "Open Image",
  2.                 "C:\\", "Image Files (*.png *.xpm *.jpg)");
  3.  
  4. if(fileName != NULL) {
  5.     label->setText("<center>" + fileName + "</center>");
  6. }

Does it means that the modal window is a bad use?

thanks again.

February 24, 2011

Andre Andre
Robot Herder
6417 posts

Arguably, most model dialogs are a design problem from a UI point of view to begin with, so in that sense the answer to your last question is “yes”.

You can open a modal dialog and still let the eventloop continue. Read up on the documentation of QDialog for tips on that. However, that will mean re-thinking your application flow, because the call to show the dialog will return immediately. The problem is, that especially for file dialogs on windows, you really want to use the static methods like you do in order to get the native file dialogs. And those are blocking by design. A bit of a catch 22, I’m afraid.

One way out could be – dare I say it? – multithreading. If you put your networking code in a thread of its own, you can have your UI code show all the modal, blocking dialogs you want and still not stop the networking thread. However, threading brings its own set of problems and can get you into trouble real fast if you’re not careful what you’re doing.

February 24, 2011

javid javid
Lab Rat
6 posts

Thank you Andre.

I’ve tried to use multithread to tackle it before. But, as I say, When I put a socket to a thread , and make it continuously listen the tcp message, qt still shows the warning, “QSocketNotifier: socket notifiers cannot be disabled from another thread”.

Here’s the code snippet :

  1. void QxSocketThread::run(){
  2.  const int Timeout = 60 * 1000;
  3.  
  4.  while(1){
  5.   QString command = "";
  6.   while (_socket->getSocket()->bytesAvailable() < (int)sizeof(quint16)) {
  7.    if (!_socket->getSocket()->waitForReadyRead(Timeout)) {
  8.     //emit error(_socket->getSocket()->error(), _socket->getSocket()->errorString());
  9.     return;
  10.    }
  11.   }
  12.   quint16 blockSize;
  13.   QDataStream in(_socket->getSocket());
  14.   in.setVersion(QDataStream::Qt_4_0);
  15.   in >> blockSize;
  16.    
  17.   while (_socket->getSocket()->bytesAvailable() < blockSize) {
  18.    if (!_socket->getSocket()->waitForReadyRead(Timeout)) {
  19.     //emit error(_socket->getSocket()->error(), _socket->getSocket()->errorString());
  20.     return;
  21.    }
  22.   }
  23.   in >> command;
  24.    
  25.   MyCommandParser::getInstance()->parse(command);
  26.   msleep(50);
  27.  }
  28. }

When the socket is connected (signaled in main thread), I put it t to another thread, and start it.
Does anybody meet this problem?

One more question, follow this flow :
1. main thread : open a modal dialog (execute it in a slot function).
2. my thread : receive tcp message, and try to update ui, emit a signal to ui object.
3. main thread : close the modal dialog.
4. Does the ui will be updated?

I just wondering whether signal-slot is asynchronous or not?
At step 1, this slot is blocking be the “dialog.exec()”,
At step 2, there’s another signal be emitted.
Will qt handle this signal immediately? or it will hand this signal after the modal dialog be closed?

thank you all guys again.

February 24, 2011

Andre Andre
Robot Herder
6417 posts

Ehm… yes. Well, it seems that You Are Doing It Wrong ™.

The (now) recommended way to use threading, is to use QThread as-is. Don’t subclass it, but instead push a parent-less, QObject-derived worker object to the newly created thread to make it do its work in that thread.

This wiki article gives an overview of your options and pitfalls: http://developer.qt.nokia.com/wiki/Threads_Events_QObjects

Edit:

On your last question:

Signal-slot can be asynchronous. There are basically three connection modes:

  • a direct connection: this is a synchronous connection. Connected slots are executed immediately.
  • an queued connection: this is an asynchronous connection. Signals are marchalled as an event on the event loop of the receiving object, and executed when that event is processed by that event loop. The caller will continue executing immediately.
  • a blocking queued connection: same as the above, but execution of the calling code halts until all connected slots have finished executing.

The standard connection type is autoConnection. This type works as a direct connection in the normal, non-threaded case. When a signal crosses a thread-boundary (that is, the thread affinity of the sending object and of the receiving object are not the same), auto connection uses a queued connection.

October 21, 2011

arianoo arianoo
Lab Rat
19 posts

if u create the my thread(tcp thread) inside your main thread and run it from that thread not other classes and if u also connect the signals and slots in your main thread and manage all events in that i think ur problem will be solved.
u should pay attention to start the tcp thread from ur main thread and no where else and to create it there and add this class to the header of your main thread
i think if u do this exactly your program will work correclty

October 21, 2011

Andre Andre
Robot Herder
6417 posts

Eh? Why are you necroposting? This topic has been dead for about eight months. I guess if the poster still had a problem, he would have replied by now…

October 21, 2011

Lukas Geyer Lukas Geyer
Lab Rat
2074 posts

I guess you’ve meant necroposting ;-)

October 21, 2011

Andre Andre
Robot Herder
6417 posts

Lukas Geyer wrote:
I guess you’ve meant necroposting ;-)

Shame
Yes, I totally meant that. I have corrected the offending posting, and apologize if anyone was offended by it.

 
  ‹‹ Question of style: QT Dev Environment      [SOLVED]MS Word file - PrintOut method ››

You must log in to post a reply. Not a member yet? Register here!