0

I am writing a function to communicate with a test server that I didn't write. I send a command, and need to immediately capture the multi-line response before doing anything else. Of course, I'd like to not block my whole UI, which shouldn't be a problem as the response is only a few nominal ms behind when I send the command.

That being said, this is what I've come up with:

 QByteArray MainWindow::ask(const QByteArray &cmd) //blocking function. Add     to thread while in use?
 {
      this->consoleWindow->put_data_in_console(cmd);
      this->socket->write(cmd + "\r\n");

      QByteArray resBuffer;
      socket->waitForReadyRead();

      while(socket->bytesAvailable > 0)
      {
           resBuffer.append(socket->readAll());
      }
      return resBuffer;

}

But I'm only able to capture the first line of my four-line response.

Thanks in advance!

Rachael
  • 1,965
  • 4
  • 29
  • 55
  • 1
    Coming over from [the similar question where you asked me about help here](http://stackoverflow.com/questions/14189015), I have to say the same than over there: you need to have some kind of delimiter or anything which tells you on the receiver side when a respond ends. What kind of protocol does the server use? – leemes Feb 05 '15 at 22:56
  • It's TCP, and it's coming from a test machine (so I don't know what the format of the packets is exactly). I intend to ask the the server a question (in an ask function) and immediately return the result which will consist of several, variable lines of ascii text where each line ends with "\r\n" or "\n\r". I will know how many lines the response will be. I have successfully async captured each line as it each is sent by the server on each readyRead() signal, but I need to capture all lines following my question command within the "ask" function, not in an onReadyRead()-type slot. Thank you – Rachael Feb 05 '15 at 23:42
  • Why don't you just use Wireshark or tcpdump to look what's going "through the wire"? Then you don't have to guess and you can change your code accordingly – Rob Feb 16 '15 at 12:54

2 Answers2

0

If the other end is sending the response one line at a time, it's possible the response is coming over multiple packets. In between each packet, you will exhaust the available data to read on the socket, and bytesAvailable will return 0. What you actually want is to wait until the socket is closed.

I'm not too familiar with Qt, but I think something like this is what you want:

QByteArray MainWindow::ask(const QByteArray &cmd)
{
    this->consoleWindow->put_data_in_console(cmd);
    this->socket->write(cmd + "\r\n");

    QByteArray resBuffer;
      socket->waitForReadyRead();

    while(socket->isOpen())
    {
        socket->waitForReadyRead(-1);
        resBuffer.append(socket->readAll());
    }
    return resBuffer;
}

If you want to have a single connection for multiple ask/responses, you need some sort of magic delimiter to mark the end of responses and scan your buffer for it.

0

Let's assume that the server sends its responses line by line.

  1. The first line (or maybe even only a part of it, say, one byte) arrives.
  2. waitForReadyRead() unblocks.
  3. Your program enters the loop, because bytesAvailable > 0. (This check is unnecessary: Without avaiable bytes, waitForReadyRead() would still block.)
  4. readAll() reads the first line.
  5. The loop condition is checked for the second time: bytesAvailable == 0
  6. The method ends, returning only the first line.

Why don't you use readLine?

hagello
  • 2,843
  • 2
  • 27
  • 37