简体   繁体   中英

Wait for response from server on client

I'm trying to validate a user's login, so I send a username and password to the server, the server checks that data against the database, and will send a yes/no if the validation was a success or failure. The client receives this and the readyRead() signal is emitted, and I handle that with a slot.

I have this login function:

bool Client::login(QString username, QString password){

    //some code

    client.write(clientSendBuf); //send the data to the server
    //wait for response
    //if response is good, return true
    //else return false
}

I want to wait for a response from the server before I return a true or false with login . I know how to accept a response from the server just fine, but I basically want the data to be sent, and the client program to stop until either we get a response or some time has passed and we get a time out.

How do I do this in Qt?

http://qt-project.org/doc/qt-4.8/qiodevice.html#waitForReadyRead

QTcpSocket client;

if(client.waitForReadyRead(15000)){
    //do something if signal is emitted
}
else{
    //timeout
}

I didn't look through the docs properly. I found my answer.

You really do not want to write code like that. Remember that all waitFor... and exec methods can reenter your code and thus are a source of hard to find bugs. No, they will reenter at the most inopportune moment. Perhaps when you're demoing to a client, or perhaps when you've shipped your first system to Elbonia :)

The client should emit a signal when the login succeeds. There's a request to login, and a response to such a request. You can use the QStateMachine to direct the overall application's logic through such responses.

The example below presumes that the network protocol supports more than one request "on the wire" at any time. It'd be simple to get rid of the handler queue and allow just one handler.

class Client : public QObject {
  Q_OBJECT
  typedef bool (Client::*Handler)(); // returns true when the request is finished
  QTcpSocket m_client;
  QByteArray m_buffer;
  QQueue<Handler> m_responses; // always has the idle response on the bottom
  ...
  Q_SLOT void hasData() {
    Q_ASSERT(! m_responses.isEmpty());
    m_buffer += m_client.readAll();
    while (! m_buffer.isEmpty()) {
      if (m_reponses.head()()) m_responses.dequeue();
    }
  }
  bool processIdleRsp() {
    // Signal an error condition, we got data but expect none!
    return false; // Must never return true, since this response mustn't be dequeued.
  }
  bool processLoginRsp() {
    const int loginRspSize = ...;
    if (m_buffer.size() < loginRspSize) return false;
    bool success = false;
    ... // process the response
    emit loginRsp(success);
    m_buffer = m_buffer.mid(loginRspSize); // remove our response from the buffer
    return true;
  }
public:
  Client(QObject * parent = 0) : QObject(parent), m_state(Idle) {
    connect(&m_client, SIGNAL(readyRead()), SLOT(hasData());
    m_responses.enqueue(&Client::processIdleRsp);
  }
  Q_SLOT void loginReq(const QString & username, const QString & password) {
    QByteArray request;
    QDataStream req(&request, QIODevice::WriteOnly);
    ...
    m_client.write(request);
    m_responses.enqueue(&Client::processLoginRsp);
  }
  Q_SIGNAL void loginRsp(bool success);
};

You could use a circular queue for the buffer to speed things up if you're transmitting lots of data. As-is, the remaining data is shoved to the front of the buffer after each response is processed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM