QTcpSocket :: readAll()为空

时间:2017-06-13 17:16:20

标签: c++ qt qtcpsocket qtcpserver qdatastream

我是Qt的新手,我有点挣扎。我正在尝试使用QTcpSocket从客户端向服务器发送字符串。

客户方:

QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_0);
out << name;

tSock->connectToHost(ipAddress, portNumb.toInt());
tSock->waitForConnected();
tSock->write(block); // block is not empty
tSock->flush();

服务器端:

void Server::readyRead()
{
    QByteArray block;
    QDataStream out(&block, QIODevice::ReadOnly);
    out << tcpSocket->readAll();
    QString name(block); // block is empty
    players.insert(name, tcpSocket);
    std::cout << "name: " << name.toStdString(); // TODO remove
}

在服务器端,程序在收到数据时输入readyRead(),但是块为空,尽管在调用tSock->write(block)时客户端块不为空...在哪里似乎是问题?我将不胜感激任何帮助。谢谢!

3 个答案:

答案 0 :(得分:2)

修改:您的错误是您以 ReadOnly 模式打开out数据流,但尝试收到的信息字节数组:

void Server::readyRead()
{
    QByteArray block;
    QDataStream out(&block, QIODevice::ReadOnly); // !mistake, WriteOnly mode is needed
    out << tcpSocket->readAll(); // this is write operation
    //...
}

附加:请注意,Serialization mechanism of Qt Data Types在这种情况下很有用:

tSock->write(block); // this is write just a raw data of the block, not the "QByteArray"

您可以使用流操作直接将必要的Qt数据类型写入套接字,而无需转换为QByteArray

// Connect firstly
tSock->connectToHost(ipAddress, portNumb.toInt());
tSock->waitForConnected();

// Then open a data stream for the socket and write to it:
QDataStream out(tSock, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_0);
out << name; // write string directly without a convertion to QByteArray

// Then you may
tSock->flush();

在客户端,然后在服务器端使用类似的流操作:

void Server::readyRead()
{
    QString name;
    QDataStream in(tcpSocket, QIODevice::ReadOnly /*or QIODevice::ReadWrite if necessary */);
    in.setVersion(QDataStream::Qt_4_0);    
    in >> name; // read the string
    //...
}

还可以读取/写入另一个Qt&lt; s / o设备:QFileQSerialPortQProcessQBuffer和其他设备。

编辑2 :无法保证在readyRead信号上您收到已发送的完整包裹。因此,请参阅下面的示例。

请注意,在实际案例中(当您在客户端 - 服务器通信中有多个不同的数据包,并且不知道您收到的几种可能的包时)通常存在使用更复杂的算法,因为通信中的readyRead事件可能会发生以下情况:

  1. 收到完整数据包
  2. 仅收到部分内容
  3. 收到几个包裹
  4. 算法的变体(Qt 4 Fortune Client Example):

    void Client::readFortune() // on readyRead
    {
        QDataStream in(tcpSocket);
        in.setVersion(QDataStream::Qt_4_0);
    
        if (blockSize == 0) {
            if (tcpSocket->bytesAvailable() < (int)sizeof(quint16))
                return;
    
            in >> blockSize;
        }
    
        if (tcpSocket->bytesAvailable() < blockSize)
            return;
    
        QString nextFortune;
        in >> nextFortune;    
    
        //...
    }
    

    Qt 4.0是Qt的旧版本,因此另见Qt 5.9 Fortune Client Example

答案 1 :(得分:0)

您的服务器似乎没有足够的时间从客户端写入数据。 请试试这个..

tcpsocket->waitForBytesWritten(1000);

答案 2 :(得分:0)

readyRead代码错误地填写了block。您还假设您将读取足够的数据来传达整个字符串。这绝不保证。当readyRead触发它时,您知道的所有内容都至少要读取一个字节。 QDataStream交易系统有助于此。

这将是一个正确的实施:

class Server : public QObject {
  Q_OBJECT
  QPointer<QTcpSocket> m_socket;
  QDataStream m_in{m_socket.data(), &QIODevice::ReadOnly};
  void onReadyRead();
public:
  Server(QTcpSocket * socket, QObject * parent = {}) :
    QObject(parent),
    m_socket(socket)
  {
    connect(socket, &QIODevice::readyRead, this, &Server::onReadyRead);
  }
}

void onReadyRead() {
  while (true) { // must keep reading as long as names are available
    QString name;
    in >> name;
    if (in.commitTransaction()) {
      qDebug << name;
      players.insert(name, &m_socket.data());
    } else
      break;
  }
};