1

I'm developing an application that uses IPC between a local server and a client application. There is nothing particular to it, as it's structured like the Qt documentation and examples.

The problem is that the client sends packets frequently and connecting/disconnecting from the server local socket (named pipe on NT) is very slow. So what I'm trying to achieve is a "persistent" connection between the two applications.

The client application connects to the local server (QLocalServer) without any problem:

void IRtsClientImpl::ConnectToServer(const QString& name)
{   
    connect(_socket, SIGNAL(connected()), this,  SIGNAL(connected()));
    _blockSize = 0;
    _socket->abort();
    _socket->connectToServer(name, QIODevice::ReadWrite);
}

And sends requests also in the traditional Qt manner:

void IRtsClientImpl::SendRequest( quint8 cmd, const QVariant* const param_array, 
                                 unsigned int cParams )
{
    // Send data through socket

    QByteArray hdr(PROTO_BLK_HEADER_PROJ);
    QByteArray dataBlock;
    QDataStream out(&dataBlock, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_5);

    quint8 command = cmd;

    out << blocksize_t(0)   // block size
        << hdr      // header
        << quint32(PROTO_VERSION_PROJ) // protocol version
        << command            // command
        << cParams;           // number of valid parameters

    for (unsigned int i = 0; i < cParams; ++i)
        out << param_array[i];

    // Write the current block size
    out.device()->seek(0);
    out << dataBlock.size() - sizeof(blocksize_t);
    _socket->write(dataBlock);
}

No problem. But the trick resides on the readyRead() signal in the server-side. Here's the current implementation of the readyRead() handling slot:

void IRtsServerImpl::onReadyRead()
{
    QDataStream in(_lsock);
    in.setVersion(QDataStream::Qt_4_5);

    if (_blocksize == 0)
    {
        qDebug("Bytes Available on socket: %d", _lsock->bytesAvailable());
        if (_lsock->bytesAvailable() < sizeof(blocksize_t))
            return;

        in >> _blocksize;
    }

    // We need more data?
    if (_lsock->bytesAvailable() < _blocksize)
        return;

    ReadRequest(in);

    // Reset
    _blocksize = 0; 

}

Without setting _blocksize to zero I could not receive more data, only the first block group (I would expect an entire block to arrive without segmentation since this is through a pipe, but it does not, go figure). I expect that behavior, sure, since the _blocksize does not represent the current stream flow anymore. All right, resetting _blocksize does the trick, but I can't resend another packet from the client without getting an increasing array of bytes on the socket. What I want is to process the request in ReadRequest and receive the next data blocks without resorting to connecting/reconnecting the applications involved.

Maybe I should 'regulate' the rate of the incoming data?

Thank you very much.

Hernán
  • 4,527
  • 2
  • 32
  • 47
  • 2
    A couple of questions: 1. Why are you aborting the socket before connecting? 2. Shouldn't you be reading all the bytes available in your onReadyRead method? The readyRead() signal will be only emitted again if more data arrives. (There should be a loop in there to process queued messages as there could probably be more than one.) – andref Dec 08 '09 at 17:34
  • 1) Dont care about the abort, it was there to test if existing connections with same server name should close previous to connect. 2) I read up to _blockSize bytes, which are sent in the block header. If more than _blockSize bytes arrive, with ReadAll() I think you can read past a valid block. – Hernán Dec 08 '09 at 21:07
  • 1
    But couldn't you have a buffer as a member variable where you read the data away? Now, if there is more than one whole block available when onReadyRead() is called, only the first one is read away. I guess you are sure that the ReadRequest() reads exactly _blockSize bytes and not a single byte more, i.e. the reader can't get out of sync? – Timo Metsälä Dec 08 '09 at 22:51
  • 1
    ..have a member variable buffer, or loop through them all as @andref suggested. – Timo Metsälä Dec 08 '09 at 22:58
  • +1 for all.. a forever loop got it properly. Thank you. – Hernán Dec 09 '09 at 06:34
  • I voted to close this question. I've solved it, thank you all. – Hernán Dec 09 '09 at 20:37

0 Answers0