How to get QByteArray from QDataStream?
-
Hello everyone, I want the information to be written to the variable data_ (QByteArray), here is the code
void MainWindow::slotReadyRead() { QDataStream in (socket); in.setVersion(QDataStream::Qt_6_2); if (in.status() == QDataStream::Ok) { while(1) { if (next_block_size_ == 0) { if (socket->bytesAvailable() < 2) { break; } in >> next_block_size_; } if (socket->bytesAvailable() < next_block_size_) { break; } QString str; in >> str; next_block_size_ = 0; ui->textBrowser->append(str); } data_ = socket->readAll(); doc_ = QJsonDocument::fromJson(data_, &doc_error_); if (doc_error_.errorString()=="no error occurred") { if (doc_.object().value("type").toString() == "connect" && doc_.object().value("status").toString() == "YEs") { QMessageBox::information(this, "Information", "Connnect:Ok"); } else { QMessageBox::information(this, "Information", "Connnect:No"); } } else { QMessageBox::information(this, "Information", "Bad Format" + doc_error_.errorString()); } } else { ui->textBrowser->append("Error read"); } }
But when I try to do the following:
// QString str; // in >> str; in >> data_; next_block_size_ = 0; // ui->textBrowser->append(str); } // data_ = socket->readAll(); doc_ = QJsonDocument::fromJson(data_, &doc_error_);
it doesn't work
-
Hello everyone, I want the information to be written to the variable data_ (QByteArray), here is the code
void MainWindow::slotReadyRead() { QDataStream in (socket); in.setVersion(QDataStream::Qt_6_2); if (in.status() == QDataStream::Ok) { while(1) { if (next_block_size_ == 0) { if (socket->bytesAvailable() < 2) { break; } in >> next_block_size_; } if (socket->bytesAvailable() < next_block_size_) { break; } QString str; in >> str; next_block_size_ = 0; ui->textBrowser->append(str); } data_ = socket->readAll(); doc_ = QJsonDocument::fromJson(data_, &doc_error_); if (doc_error_.errorString()=="no error occurred") { if (doc_.object().value("type").toString() == "connect" && doc_.object().value("status").toString() == "YEs") { QMessageBox::information(this, "Information", "Connnect:Ok"); } else { QMessageBox::information(this, "Information", "Connnect:No"); } } else { QMessageBox::information(this, "Information", "Bad Format" + doc_error_.errorString()); } } else { ui->textBrowser->append("Error read"); } }
But when I try to do the following:
// QString str; // in >> str; in >> data_; next_block_size_ = 0; // ui->textBrowser->append(str); } // data_ = socket->readAll(); doc_ = QJsonDocument::fromJson(data_, &doc_error_);
it doesn't work
@Idodoqdo said in How to get QByteArray from QDataStream?:
it doesn't work
What does this mean?
If you comment out putting anything in
data_
what should you/we expect?If you expect
data_ = socket->readAll();
to definitely have read the whole of the data bytes for the JSON document to parse there is no guarantee it will have done so, as has been discussed many times in this forum. -
@Idodoqdo said in How to get QByteArray from QDataStream?:
it doesn't work
What does this mean?
If you comment out putting anything in
data_
what should you/we expect?If you expect
data_ = socket->readAll();
to definitely have read the whole of the data bytes for the JSON document to parse there is no guarantee it will have done so, as has been discussed many times in this forum. -
@Idodoqdo
To useQDataStream
to read data that data must have been written into aQDataStream
by the sender. Is that really the case here? Only you know what the sender is. If it is not a Qt program usingQDataStream
to write its data then you cannot useQDataStream
as you are doing to read it. If it is, the reader can only read back exactly the same type as was written to it. If you are sayingQString str; in >> str;
does work correctly, then what is in the stream is a
QString
. If you try to read it as aQByteArray
that won't work.So first things first: verify your other side is indeed sending a
QString
? Then that is what you must read from the stream, and work from there.Reading, say, https://www.qtcentre.org/threads/71559-QDataStream-to-QByteArray-and-ViceVersa might be of some help.
-
@Idodoqdo
To useQDataStream
to read data that data must have been written into aQDataStream
by the sender. Is that really the case here? Only you know what the sender is. If it is not a Qt program usingQDataStream
to write its data then you cannot useQDataStream
as you are doing to read it. If it is, the reader can only read back exactly the same type as was written to it. If you are sayingQString str; in >> str;
does work correctly, then what is in the stream is a
QString
. If you try to read it as aQByteArray
that won't work.So first things first: verify your other side is indeed sending a
QString
? Then that is what you must read from the stream, and work from there.Reading, say, https://www.qtcentre.org/threads/71559-QDataStream-to-QByteArray-and-ViceVersa might be of some help.
@JonB
The client and server programs are written in qt
this is how the server sends:auto Server::SendToClient(QString str) -> void { data_.clear(); QDataStream out(&data_, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_6_2); out << quint16(0) << str; out.device()->seek(0); out.device()->seek(data_.size() - sizeof(quint16)); for (int i = 0; i < Sockets.size(); ++i) { auto socket = QPointer<QTcpSocket>(Sockets.at(i)); if (socket) { socket->write(data_); } else { Sockets.removeOne(socket); } } }
-
@JonB
The client and server programs are written in qt
this is how the server sends:auto Server::SendToClient(QString str) -> void { data_.clear(); QDataStream out(&data_, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_6_2); out << quint16(0) << str; out.device()->seek(0); out.device()->seek(data_.size() - sizeof(quint16)); for (int i = 0; i < Sockets.size(); ++i) { auto socket = QPointer<QTcpSocket>(Sockets.at(i)); if (socket) { socket->write(data_); } else { Sockets.removeOne(socket); } } }
@Idodoqdo said in How to get QByteArray from QDataStream?:
out << quint16(0) << str; out.device()->seek(0); out.device()->seek(data_.size() - sizeof(quint16));
Then do the opposite on your site. But, as @JonB already mentions make sure that you really got all bytes before trying to receive the string. For this e.g. use a custom buffer or take a look at QDataStream::startTransaction(). A forum search for this will also help: https://forum.qt.io/search?term=qdatastream starttransaction&in=posts&matchWords=all&sortBy=relevance&sortDirection=desc&showAs=posts
-
@JonB
The client and server programs are written in qt
this is how the server sends:auto Server::SendToClient(QString str) -> void { data_.clear(); QDataStream out(&data_, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_6_2); out << quint16(0) << str; out.device()->seek(0); out.device()->seek(data_.size() - sizeof(quint16)); for (int i = 0; i < Sockets.size(); ++i) { auto socket = QPointer<QTcpSocket>(Sockets.at(i)); if (socket) { socket->write(data_); } else { Sockets.removeOne(socket); } } }
@Idodoqdo
As @Christian-Ehrlicher has written about the issue of making sure you collect all bytes in the stream before sending it for parsing as a JSON document.Although it does not matter, why does your code do the
out << quint16(0) << str; out.device()->seek(0); out.device()->seek(data_.size() - sizeof(quint16));
seeking? What are you trying to achieve by writing a 16-bit
0
followed by aQString
and then seeking to the end of the stream minus the size of aquint16
? That will be two bytes before the end of theQString
, what's the objective?? -
@Idodoqdo
As @Christian-Ehrlicher has written about the issue of making sure you collect all bytes in the stream before sending it for parsing as a JSON document.Although it does not matter, why does your code do the
out << quint16(0) << str; out.device()->seek(0); out.device()->seek(data_.size() - sizeof(quint16));
seeking? What are you trying to achieve by writing a 16-bit
0
followed by aQString
and then seeking to the end of the stream minus the size of aquint16
? That will be two bytes before the end of theQString
, what's the objective?? -
@JonB
I just want my client and server to communicate using Json. Maybe I don't even need QString. I want the client and server to read the data in full@Idodoqdo said in How to get QByteArray from QDataStream?:
I want the client and server to read the data in full
You must read what I & @Christian-Ehrlicher said about buffering the incoming data, read the links he has given you in his post.
I also don't know what you are trying to achieve with the
quint16(0)
and theseek()
ing, but it does not look right. -
@Idodoqdo said in How to get QByteArray from QDataStream?:
I want the client and server to read the data in full
You must read what I & @Christian-Ehrlicher said about buffering the incoming data, read the links he has given you in his post.
I also don't know what you are trying to achieve with the
quint16(0)
and theseek()
ing, but it does not look right.@JonB
At the moment, my client and server understand each other. What do you think: can it be left as it is, or is it still worth changing something? (I mean about the sending and receiving mechanism)
Server:#include "server.h" Server::Server() : next_block_size_(0) { if (listen(QHostAddress::Any, 2323)) { qDebug() << "start"; } else { qDebug() << "error"; } db_ = QSqlDatabase::addDatabase("QPSQL"); db_.setHostName("localhost"); db_.setDatabaseName("postgres"); db_.setUserName("postgres"); db_.setPassword("12345"); qDebug() << QSqlDatabase::drivers(); if (db_.open()) { qDebug() << "db open"; } else { qDebug() << "db not open"; } } auto Server::SendToClient(QByteArray str) -> void { // data_.clear(); // QDataStream out(&data_, QIODevice::WriteOnly); // out.setVersion(QDataStream::Qt_6_2); // out << quint16(0) << str; // out.device()->seek(0); // out.device()->seek(data_.size() - sizeof(quint16)); for (int i = 0; i < Sockets.size(); ++i) { auto socket = QPointer<QTcpSocket>(Sockets.at(i)); if (socket) { socket->write(str); } else { Sockets.removeOne(socket); } } } auto Server::MessageProcessing(QByteArray message) -> void { doc_ = QJsonDocument::fromJson(message, &doc_error_); if (doc_error_.errorString()=="no error occurred") { if (doc_.object().value("type").toString() == "auth") { QByteArray result = "{\"type\":\"resultSelect\",\"result\":"; QSqlQuery * query = new QSqlQuery(db_); query->prepare("select id from users where login = :login and pass = :pass;"); query->bindValue(":login", "\'" + doc_.object().value("login").toString() + "\'"); query->bindValue(":pass:", "\'" + doc_.object().value("pass").toString()); if (query->exec()) { query->next(); if (query->isNull(0)) { result.append("\"no\"}"); } else { result.append("\"yes\"}"); } SendToClient(result); } else { qDebug() << "invalid query"; } } } else { qDebug() << "Error read message"; } } auto Server::incomingConnection(qintptr socketDescriptor) -> void { qDebug() << "hello"; socket = new QTcpSocket; socket->setSocketDescriptor(socketDescriptor); connect(socket, &QTcpSocket::readyRead, this, &Server::slotReadyRead); connect(socket, &QTcpSocket::disconnected, this, &Server::Disconnect); Sockets.push_back(socket); qDebug() << "client connected" << socketDescriptor; socket->write("{\"type\":\"connect\",\"status\":\"YEs\"}"); } auto Server::slotReadyRead() -> void { socket = (QTcpSocket*)sender(); QDataStream in(socket); in.setVersion(QDataStream::Qt_6_2); if (in.status() == QDataStream::Ok) { qDebug() << "read ..."; while(1) { if (next_block_size_ == 0) { if (socket->bytesAvailable() < 2) { break; } in >> next_block_size_; } if (socket->bytesAvailable() < next_block_size_) { break; } QString str; in >> str; next_block_size_ = 0; MessageProcessing(str.toUtf8()); // SendToClient(str); break; } } else { qDebug() << "Error DataStream"; } } auto Server::Disconnect() -> void { auto socket = qobject_cast<QTcpSocket*>(sender()); if (socket) { Sockets.removeOne(socket); socket->deleteLater(); } }
Client:
#include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); socket = nullptr; connect(ui->ConnectToServer, SIGNAL(released()), this, SLOT(Connect())); connect(ui->Auth, SIGNAL(clicked()), this, SLOT(Authorization())); } MainWindow::~MainWindow() { delete ui; } void MainWindow::Connect() { if (socket == nullptr) { socket = new QTcpSocket(this); connect(socket, &QTcpSocket::readyRead, this, &MainWindow::slotReadyRead); connect(socket, &QTcpSocket::disconnected, this, &MainWindow::Disconnect); qDebug() << "press connect"; next_block_size_ = 0; socket->connectToHost("127.0.0.1", 2323); if(!socket->waitForConnected(5000)) { qDebug() << "Error: " << socket->errorString(); delete socket; socket = nullptr; } } } void MainWindow::Authorization() { auth_ = new AuthorizationView; connect(auth_, &AuthorizationView::InfoAuth, this, &MainWindow::AuthInfo); auth_->setModal(true); auth_->exec(); } void MainWindow::Disconnect() { socket->deleteLater(); socket = nullptr; } void MainWindow::SendToServer(QString str) { if (socket != nullptr) { data_.clear(); QDataStream out(&data_, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_6_2); out << quint16(0) << str; out.device()->seek(0); out.device()->seek(data_.size() - sizeof(quint16)); socket->write(data_); ui->lineEdit->clear(); } } void MainWindow::slotReadyRead() { QDataStream in (socket); in.setVersion(QDataStream::Qt_6_2); if (in.status() == QDataStream::Ok) { // while(1) { // if (next_block_size_ == 0) { // if (socket->bytesAvailable() < 2) { // break; // } // in >> next_block_size_; // } // if (socket->bytesAvailable() < next_block_size_) { // break; // } // QString str; // in >> str; // next_block_size_ = 0; // ui->textBrowser->append(str); // break; // } data_ = socket->readAll(); doc_ = QJsonDocument::fromJson(data_, &doc_error_); if (doc_error_.errorString()=="no error occurred") { if (doc_.object().value("type").toString() == "connect" && doc_.object().value("status").toString() == "YEs") { QMessageBox::information(this, "Information", "Connnect:Ok"); } else { QMessageBox::information(this, "Information", "Connnect:No"); } if (doc_.object().value("type").toString() == "resultSelect") { if (doc_.object().value("result") == "yes") { ui->textBrowser->append("client exist"); } else { ui->textBrowser->append("client no exist"); } } } else { QMessageBox::information(this, "Information", "Bad Format" + doc_error_.errorString()); } } else { ui->textBrowser->append("Error read"); } } void MainWindow::AuthInfo(QPair<QString, QString> info) { SendToServer("{\"type\":\"auth\",\"login\":\"" + info.first + "\"," + "\"pass\":\"" + info.second + "\"}"); }
-
@JonB
At the moment, my client and server understand each other. What do you think: can it be left as it is, or is it still worth changing something? (I mean about the sending and receiving mechanism)
Server:#include "server.h" Server::Server() : next_block_size_(0) { if (listen(QHostAddress::Any, 2323)) { qDebug() << "start"; } else { qDebug() << "error"; } db_ = QSqlDatabase::addDatabase("QPSQL"); db_.setHostName("localhost"); db_.setDatabaseName("postgres"); db_.setUserName("postgres"); db_.setPassword("12345"); qDebug() << QSqlDatabase::drivers(); if (db_.open()) { qDebug() << "db open"; } else { qDebug() << "db not open"; } } auto Server::SendToClient(QByteArray str) -> void { // data_.clear(); // QDataStream out(&data_, QIODevice::WriteOnly); // out.setVersion(QDataStream::Qt_6_2); // out << quint16(0) << str; // out.device()->seek(0); // out.device()->seek(data_.size() - sizeof(quint16)); for (int i = 0; i < Sockets.size(); ++i) { auto socket = QPointer<QTcpSocket>(Sockets.at(i)); if (socket) { socket->write(str); } else { Sockets.removeOne(socket); } } } auto Server::MessageProcessing(QByteArray message) -> void { doc_ = QJsonDocument::fromJson(message, &doc_error_); if (doc_error_.errorString()=="no error occurred") { if (doc_.object().value("type").toString() == "auth") { QByteArray result = "{\"type\":\"resultSelect\",\"result\":"; QSqlQuery * query = new QSqlQuery(db_); query->prepare("select id from users where login = :login and pass = :pass;"); query->bindValue(":login", "\'" + doc_.object().value("login").toString() + "\'"); query->bindValue(":pass:", "\'" + doc_.object().value("pass").toString()); if (query->exec()) { query->next(); if (query->isNull(0)) { result.append("\"no\"}"); } else { result.append("\"yes\"}"); } SendToClient(result); } else { qDebug() << "invalid query"; } } } else { qDebug() << "Error read message"; } } auto Server::incomingConnection(qintptr socketDescriptor) -> void { qDebug() << "hello"; socket = new QTcpSocket; socket->setSocketDescriptor(socketDescriptor); connect(socket, &QTcpSocket::readyRead, this, &Server::slotReadyRead); connect(socket, &QTcpSocket::disconnected, this, &Server::Disconnect); Sockets.push_back(socket); qDebug() << "client connected" << socketDescriptor; socket->write("{\"type\":\"connect\",\"status\":\"YEs\"}"); } auto Server::slotReadyRead() -> void { socket = (QTcpSocket*)sender(); QDataStream in(socket); in.setVersion(QDataStream::Qt_6_2); if (in.status() == QDataStream::Ok) { qDebug() << "read ..."; while(1) { if (next_block_size_ == 0) { if (socket->bytesAvailable() < 2) { break; } in >> next_block_size_; } if (socket->bytesAvailable() < next_block_size_) { break; } QString str; in >> str; next_block_size_ = 0; MessageProcessing(str.toUtf8()); // SendToClient(str); break; } } else { qDebug() << "Error DataStream"; } } auto Server::Disconnect() -> void { auto socket = qobject_cast<QTcpSocket*>(sender()); if (socket) { Sockets.removeOne(socket); socket->deleteLater(); } }
Client:
#include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); socket = nullptr; connect(ui->ConnectToServer, SIGNAL(released()), this, SLOT(Connect())); connect(ui->Auth, SIGNAL(clicked()), this, SLOT(Authorization())); } MainWindow::~MainWindow() { delete ui; } void MainWindow::Connect() { if (socket == nullptr) { socket = new QTcpSocket(this); connect(socket, &QTcpSocket::readyRead, this, &MainWindow::slotReadyRead); connect(socket, &QTcpSocket::disconnected, this, &MainWindow::Disconnect); qDebug() << "press connect"; next_block_size_ = 0; socket->connectToHost("127.0.0.1", 2323); if(!socket->waitForConnected(5000)) { qDebug() << "Error: " << socket->errorString(); delete socket; socket = nullptr; } } } void MainWindow::Authorization() { auth_ = new AuthorizationView; connect(auth_, &AuthorizationView::InfoAuth, this, &MainWindow::AuthInfo); auth_->setModal(true); auth_->exec(); } void MainWindow::Disconnect() { socket->deleteLater(); socket = nullptr; } void MainWindow::SendToServer(QString str) { if (socket != nullptr) { data_.clear(); QDataStream out(&data_, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_6_2); out << quint16(0) << str; out.device()->seek(0); out.device()->seek(data_.size() - sizeof(quint16)); socket->write(data_); ui->lineEdit->clear(); } } void MainWindow::slotReadyRead() { QDataStream in (socket); in.setVersion(QDataStream::Qt_6_2); if (in.status() == QDataStream::Ok) { // while(1) { // if (next_block_size_ == 0) { // if (socket->bytesAvailable() < 2) { // break; // } // in >> next_block_size_; // } // if (socket->bytesAvailable() < next_block_size_) { // break; // } // QString str; // in >> str; // next_block_size_ = 0; // ui->textBrowser->append(str); // break; // } data_ = socket->readAll(); doc_ = QJsonDocument::fromJson(data_, &doc_error_); if (doc_error_.errorString()=="no error occurred") { if (doc_.object().value("type").toString() == "connect" && doc_.object().value("status").toString() == "YEs") { QMessageBox::information(this, "Information", "Connnect:Ok"); } else { QMessageBox::information(this, "Information", "Connnect:No"); } if (doc_.object().value("type").toString() == "resultSelect") { if (doc_.object().value("result") == "yes") { ui->textBrowser->append("client exist"); } else { ui->textBrowser->append("client no exist"); } } } else { QMessageBox::information(this, "Information", "Bad Format" + doc_error_.errorString()); } } else { ui->textBrowser->append("Error read"); } } void MainWindow::AuthInfo(QPair<QString, QString> info) { SendToServer("{\"type\":\"auth\",\"login\":\"" + info.first + "\"," + "\"pass\":\"" + info.second + "\"}"); }
@Idodoqdo said in How to get QByteArray from QDataStream?:
What do you think: can it be left as it is, or is it still worth changing something?
We already told you what's wrong with a single call to readAll() but you don't seem to care so do I.