problems with QByteArray and QString convertion - c++

I've got a server and a client and they're connected by TCP (QTcpSocket and QTcpServer). data is sent using QByteArray.
void Receive::newConnection()
{
while (server->hasPendingConnections())
{
QTcpSocket *socket = server->nextPendingConnection();
connect(socket, SIGNAL(readyRead()), SLOT(readyRead()));
connect(socket, SIGNAL(disconnected()), SLOT(disconnected()));
QByteArray *buffer = new QByteArray();
qint32 *s = new qint32(0);
buffers.insert(socket, buffer);
sizes.insert(socket, s);
qDebug()<<buffer;
}
}
last Line prints the text entered in client in server's console. i want to convert buffer to QString. (or i want to send it to qml file). so when i try :
QString receivedText = QTextCodec::codecForMib(1015)->toUnicode(buffer);
and give me the error :
no matching function for call to 'QTextCodec::toUnicode(QByteArray*&)'
receivedText = QTextCodec::codecForMib(1015)->toUnicode(buffer);
^
when using fromAscii or fromStringC it says it's not a member of QString.
what should i do?

According to the documentation:
QString QTextCodec::toUnicode(const QByteArray &a) const
Converts a from the encoding of this codec to Unicode, and returns the
result in a QString.
From the above, it follows that the reference is needed and not the pointer. In your case you should change it to:
QString receivedText = QTextCodec::codecForMib(1015)->toUnicode(*buffer);

Related

Sending images over TCP from labVIEW to QT

I am trying to capture images taken from a camera connected to a myRIO and send them over a TCP/IP connection from labVIEW to a QT GUI application.
My problem is that QT keeps throwing a heap pointer exception and crashing when I read the data.
Expression: is_block_type_valid(header->_block_use)
I believe this could be because the data being sent is over 35k bytes, so I tried to read the data in separate chunks, but alas am still getting the error.
Below is my function that gets called on readyRead() being emitted:
void TCPHandler::onRead() {
QByteArray byteArray;
QByteArray buffer;
QByteArray dataSize = mainSocket->read(5); //read the expected amount of bytes incoming (about 35000)
while (buffer.size() < dataSize.toInt()) {
int bytesLeft = dataSize.toInt() - buffer.size();
if (bytesLeft < 1024) {
byteArray = mainSocket->read(bytesLeft);
}
else {
byteArray = mainSocket->read(1024);
}
buffer.append(byteArray);
}
QBuffer imageBuffer(&buffer);
imageBuffer.open(QIODevice::ReadOnly);
QImageReader reader(&imageBuffer, "JPEG");
QImage image;
if(reader.canRead())
image = reader.read();
else {
emit read("Cannot read image data");
}
if (!image.isNull())
{
image.save("C:/temp");
}
else
{
emit read(reader.errorString());
}}
In the LabVIEW code I send the size of the bytes being sent first, then the raw image data:
EDIT: Connect for the slot. Also should have mentioned this is running in a separate thread to the Main GUI.
TCPHandler::TCPHandler(QObject *parent)
: QObject(parent),
bytesExpected(0)
{
mainSocket = new QTcpSocket(this);
connect(mainSocket, SIGNAL(readyRead()), this, SLOT(onRead()));
connect(mainSocket, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error), this, &TCPHandler::displayError);
}
You are sending your length as a decimal string. Then followed by the string.
I would expect that the length would be binary value. So instead of an 'I32 to String' function use a typecast with a string as the type.

Simple version checker with Qt

I’m trying to implement a simple version checker below.
I’m getting a zero error code reading the file, but the file
contents show up blank. You can access the file via browser,
permissions are ok.
void check_version()
{
QNetworkAccessManager *nam = new QNetworkAccessManager();
QUrl data_url("http://www.example.com/version.txt");
QNetworkRequest req(data_url);
QNetworkReply *reply = nam->get(req);
QByteArray data = reply->readAll() ;
QString s1(data);
int err = reply->error();
QString s2 = QString::number(err);
delete reply;
delete nam;
QMessageBox::critical(0, "",s1+" "+s2,QMessageBox::Cancel);
}
I gather the problem is that I need to wait to read until the get is finished, so I need a signal and a slot: the signal tells the slot to read the data.
pseudocode:
QObject::connect(&rep, SIGNAL( rep is finished ),
QByteArray newver , SLOT( reply->readAll() ));
How do I set up a signal/slot for my task?
You're right, you have to wait until the get() is "finished" in order to obtain the whole response with a call to readAll().
Following a working example to start with:
// ...
QNetworkAccessManager *nam = new QNetworkAccessManager();
QUrl data_url("http://www.example.com/version.txt");
QNetworkReply* reply = nam->get(QNetworkRequest(data_url));
QEventLoop eventLoop;
QObject::connect(reply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
eventLoop.exec();
if (reply->error() != QNetworkReply::NoError)
{
// Something went wrong. Error can be retrieved with: reply->error()
}
else
{
// Call reply->readAll() and do what you need with the data
}
// ...
This example will block until the reply is ready. If you need an asynchronous behavior you can just connect the signal finished() to a custom slot and check for error and/or read there. I do not recommend to connect the signal finished() directly to readAll() because "sometimes errors happen".

UDP Server-Client Chat in C++/Qt

I'm trying to write a chat program using Qt. It's half completed but it has some problems.
First of all I get an error when I want to send my written message in lineedit to the client. It's a QString, but the writeDatagram only sends a QByteArray. I've googled it and there are some ways for converting QString to QByteArray, but I'm looking for a better solution.
I think I should use connectToHost(), but read() and write() don't work.
Second and main problem is that I can't get to send and receive messages continuously! Obviously this one hasn't occurred yet but I know there is something wrong with it because I've tested it on Qt console and it didn't work there too.
I'm new to GUI and Socket programming, therefore I've searched a lot before I post this topic.
Update: My first problem solved, but now the UDP packets don't get send and receive let alone working like a chat application.
Update: I found out what was the problem and I solved it. The code needed two QUdpSocket Objects. I also updated the code. It's now fully functional.
If you have other inputs I would love to listen to them, otherwise I've got my answer.
Server:
#include "schat.h"
#include "ui_schat.h"
schat::schat(QWidget *parent) :
QWidget(parent),
ui(new Ui::schat)
{
ui->setupUi(this);
socketServerc=new QUdpSocket(this);
socketServer=new QUdpSocket(this);
socketServer->bind(QHostAddress::LocalHost, 8001);
connect(socketServer,SIGNAL(readyRead()),this,SLOT(readPendingDatagrams()));
}
schat::~schat()
{
delete ui;
}
void schat::on_sendButton_clicked()
{
QString word=ui->lineEdit->text();
ui->textBrowser->append(word);
QByteArray buffer;
buffer=word.toUtf8();
QHostAddress sender;
quint16 senderPort;
socketServerc->writeDatagram(buffer.data(), QHostAddress::LocalHost, 7000 );
}
void schat::readPendingDatagrams()
{
while (socketServer->hasPendingDatagrams()) {
QByteArray buffer;
buffer.resize(socketServer->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
socketServer->readDatagram(buffer.data(), buffer.size(),&sender, &senderPort);
ui->textBrowser->append(buffer.data());
}
}
Client:
#include "uchat.h"
#include "ui_uchat.h"
uchat::uchat(QWidget *parent) :
QWidget(parent),
ui(new Ui::uchat)
{
ui->setupUi(this);
clientSocket=new QUdpSocket(this);
clientSocketc=new QUdpSocket(this);
clientSocketc->bind(QHostAddress::LocalHost, 7000);
connect(clientSocketc,SIGNAL(readyRead()),this,SLOT(readPendingDatagrams()));
}
uchat::~uchat()
{
delete ui;
}
void uchat::on_sendButton_clicked()
{
QString word=ui->lineEdit->text();
ui->textBrowser->append(word);
QByteArray buffer;
buffer.resize(clientSocket->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
buffer=word.toUtf8();
clientSocket->writeDatagram(buffer.data(), QHostAddress::LocalHost, 8001 );
}
void uchat::readPendingDatagrams()
{
while (clientSocketc->hasPendingDatagrams()) {
QByteArray buffer;
buffer.resize(clientSocketc->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
clientSocketc->readDatagram(buffer.data(), buffer.size(),&sender, &senderPort);
ui->textBrowser->append(buffer.data());
}
}
Converting the QString to a QByteArray is indeed the thing to do. The reason is that UDP packets carry only a series of bytes -- but a QString does not unambiguously represent a sequence of bytes, it represents a sequence of notional characters (a.k.a. QChars). So in order to place that QString into an array of bytes, you have to decide which binary representation you want to encode it as. For example, if you wanted to encode the string using UTF8 encoding (which I would recommend), you'd use QString's toUtf8() method to get the QByteArray representing the UTF8 encoding, and the receiver would use QString's fromUtf8() method to turn the received bytes back into a QString. There are other encodings also (ascii, latin1, local8Bit) but they may not handle internationalization as well as UTF8 does.
As for your second problem ("I can't get to send and receive messages continuously"), you're going to have to be more explicit and descriptive about what happens vs what you expected to happen. I don't know what "continuously" means in this context.

QLocalSocket to QLocalServer message being corrupted during transfer

I haven't been able to find a similar issue, so here goes:
I'm sending a QString from a QLocalSocket to a QLocalServer across two applications. The receiving (QLocalServer) application does receive the message, but it seems the encoding is completely wrong.
If I send a QString = "x" from the QLocalSocket (client), I'm getting a foreign (Chinese?) symbol in the QLocalServer. My code is literally copied from the Nokia Developer website
If I printout the message via QDebug, I get "??". If I fire it in a message box, Chinese characters are printed. I've tried re-encoding the received message to UTF-8, Latin1, etc., with no luck.
Code is as follows:
//Client
int main(int argc, char *argv[])
{
QLocalSocket * m_socket = new QLocalSocket();
m_socket->connectToServer("SomeServer");
if(m_socket->waitForConnected(1000))
{
//send a message to the server
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_7);
out << "x";
out.device()->seek(0);
m_socket->write(block);
m_socket->flush();
QMessageBox box;
box.setText("mesage has been sent");
box.exec();
...
}
//Server - this is within a QMainWindow
void MainWindow::messageReceived()
{
QLocalSocket *clientConnection = m_pServer->nextPendingConnection();
while (clientConnection->bytesAvailable() < (int)sizeof(quint32))
clientConnection->waitForReadyRead();
connect(clientConnection, SIGNAL(disconnected()),
clientConnection, SLOT(deleteLater()));
QDataStream in(clientConnection);
in.setVersion(QDataStream::Qt_4_7);
if (clientConnection->bytesAvailable() < (int)sizeof(quint16)) {
return;
}
QString message;
in >> message;
QMessageBox box;
box.setText(QString(message));
box.exec();
}
Any help is highly appreciated.
The client is serializing a const char* while the server is deserializing a QString. These aren't compatible. The former literally writes the string bytes, the latter first encodes to UTF-16. So, I guess on the server side, the raw string data "fff" is being decoded into a QString as though it were UTF-16 data... perhaps resulting in character U+6666, 晦.
Try changing the client to also serialize a QString, i.e.
// client writes a QString
out << QString::fromLatin1("fff");
// server reads a QString
QString message;
in >> message;

QNetworkReply reply has no members in finishedSlot

Qt Creator is used as the ide for this small app that is being developed
I am attempting to use QNetworkAccessManager to retrieve some information from a website. After the request is 'posted' to the web, the finished() signal is triggered, however the pointer that is passed to the finishedSlot() function does not appear to be pointing to an instantiated object, it is just address of the ponter. The code for the button click that starts the request and the code for the finishedSlot() method is shown below.
In the watch window, I would have expected to see a triangle next to 'reply' that when expaned would show all the data member of QNetworkReply object. Instead it has a single value of #0x80c770 which looks like the pointer address.
I'd appreciate input from anyone who can help me to understand why my pointer doesn't appeart to be pointing the the QNetworkReply object.
void MainWindow::on_btnGetOAuthToken_clicked()
{
QUrl serviceUrl("https://api.ProPhotoWebsite.com/services/oauth/authorize.mg");
QUrl postData;
postData.addQueryItem("method", "ProPhotoWebsite.auth.getRequestToken");
postData.addQueryItem("oauth_consumer_key", "AAAAAAAAAAAAAAAAAAAAAAAA"); //example key
postData.addQueryItem("oauth_nonce",QUuid::createUuid().toString());
postData.addQueryItem("oauth_signature_method","PLAINTEXT");
postData.addQueryItem("oauth_signature","999999999999999999999999999"); //example
postData.addQueryItem("oauth_timestamp", QString::number(QDateTime::currentMSecsSinceEpoch()/1000));
postData.addQueryItem("oauth_version","1.0");
//...
QNetworkRequest request(serviceUrl);
request.setHeader(QNetworkRequest::ContentTypeHeader,
"application/x-www-form-urlencoded");
// Call the webservice
QNetworkAccessManager *nam = new QNetworkAccessManager(this);
connect(nam, SIGNAL(finished(QNetworkReply*)),
SLOT(finishedSlot(QNetworkReply*)));
nam->post(request,postData.encodedQuery());
}
void MainWindow::finishedSlot(QNetworkReply *reply)
{
// Reading attributes of the reply
// e.g. the HTTP status code
QVariant statusCodeV =
reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
// Or the target URL if it was a redirect:
QVariant redirectionTargetUrl =
reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
// see CS001432 on how to handle this
// no error received?
if (reply->error() == QNetworkReply::NoError)
{
QByteArray bytes = reply->readAll(); // bytes
QString string(bytes); // string
ui->lblWarning->setText(string);
}
else
{
// handle errors here
}
// need to dispose reply
delete reply;
}