1

I'm puzzled with a problem designing a simple QLocalServer-QLocalSocket IPC system.

The QLocalServer waits for a new connection and connect the signals to the proper slots.

void CommandProcessor::onNewConnection()
{
    QLocalSocket* pLocal = _server->nextPendingConnection();

    connect(pLocal,SIGNAL(disconnected()),this,SLOT(onSocketDisconnected()));
    connect(pLocal,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead()));
    connect(pLocal,SIGNAL(error(QLocalSocket::LocalSocketError)),this, SLOT(onSocketError(QLocalSocket::LocalSocketError)));

    qDebug("Socket connected. addr=%p", pLocal);
}

The readyRead slot implementation is:

void CommandProcessor::onSocketReadyRead() 
{
    QLocalSocket* pLocalSocket = (QLocalSocket *) sender();
    qDebug("SocketReadyRead. addr=%p", pLocalSocket);

    QDataStream in(pLocalSocket);
    in.setVersion(QDataStream::Qt_5_2);
    pLocalSocket->readAll(); 


    qDebug("%s pLocalSocket->bytesAvailable() = %d", Q_FUNC_INFO, pLocalSocket->bytesAvailable());
}

This readAll is done intentionally to check how i'm getting two readyRead signals in sequence (from the same slot pointer, I verified that).

The client operation is fairly straightforward:

   QByteArray data;
    QDataStream out(&data, QIODevice::ReadWrite);
    out.setVersion(QDataStream::Qt_5_2);

    cmd.toDataStream(out);

    // write blocksize at first field

    out.device()->seek(0);
    out << data.size() - sizeof(BLOCKSIZE_T);
    qint64 bw = _socket->write(data);

The _socket->write(data) call triggers duplicate readyRead at server (even when the server side has read all data with ReadAll call).

Any indication of where I should look?

Hernán
  • 4,527
  • 2
  • 32
  • 47

1 Answers1

2

The semantics of QIODevice are such that readyRead signal simply means that there is likely data to be available for reading. It doesn't mean that there's surely data available, and it doesn't mean that a particular amount of data is guaranteed to be available. Implementations certainly do their best to avoid spurious signals, but they are free to issue any number of "spurious" ones. It would be a much worse problem (a bug, in fact!) if a readyRead signal was missed.

What you're supposed to do is to read whatever data is available when you get the signal. That's all. There are absolutely no guarantees that you will get the data in any particular "chunking". For example, if one end of a connection does a single, 1kByte write, the other end of the connection may get any number of readyRead signals.

All that is guaranteed is that if you only read data when you get a readyRead signal, you won't miss any data - thus you don't need to do reads from anywhere but a slot connected to a readyRead signal.

So, what you're seeing is perfectly OK. You need to handle any amount of data being available when a readyRead fires. Including zero bytes.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • *"What you're supposed to do is to read whatever data is available when you get the signal"*, isn't that optional too. You'll get new signal when there's more data, so you can just check *bytesAvailable()*, and return to wait for more without reading. Handy to avoid manual buffering. – hyde Feb 12 '14 at 06:40
  • @hyde Well, that's optional if the buffering is set up to be limitless. It's device-specific. – Kuba hasn't forgotten Monica Feb 12 '14 at 07:08
  • 2
    @hyde If you don't read all of the data in `readyRead`-connected slot, you must ensure yourself that you read it sometime later. You must set up a timer, pretty much. You're not guaranteed to get another signal, unless there will me more data. So, it is practically an idiom to have to read all the data in `readyRead`. – Kuba hasn't forgotten Monica Feb 12 '14 at 14:43
  • Ok. I'm mostly thinking of a scenario, where first length of data is received (from network socket or whatever), and then length number of bytes. So in that case it's known that either that many bytes will come through, or the connection will fail. But I suppose it's safer to do read and buffer in application code, in case the expected amount of data is in some situation large, some buffer (in Qt lib or in OS) fills, and no new signal will be received. – hyde Feb 12 '14 at 15:33
  • Thank you very much, My failure was at another point in code (client-side!) -- nevertheless, i'll follow your useful and detailed tips ;) Thank you again for your help. – Hernán Feb 12 '14 at 18:11
  • 1
    @hyde That's correct, with the caveat that you're not even guaranteed that your "number of bytes" will arrive in one piece. Even then, though, the implementation of a timeout is upon yourself. – Kuba hasn't forgotten Monica Feb 12 '14 at 18:27