qt c++ send 6 bytes using tcp protocol - c++

Hi everybody, first of all I'm new on network programming so maybe this is a simple question, but I don't get it. I try to send 6 Bytes to a microcontroller using tcp socket. In order to serialize my data I'm using qdatastream and qbytearray. That's the way I try to do this:
QByteArray buffer;
QDataStream outputStream(&buffer, QIODevice::WriteOnly);
outputStream.setVersion(QDataStream::Qt_5_8);
outputStream << (quint8) 0
<< (quint8) dataMessage.prefix
<< (quint8) dataMessage.paramID
<< (quint32) dataMessage.data;
outputStream.device()->seek(0);
outputStream << (quint8)(buffer.size() - sizeof(quint8));
qDebug() << buffer;
qDebug() << quint32(dataMessage.data);
sock->write(buffer);
if(sock->write(buffer) == -1)
{
return -1;
}
sock->flush();
My struct dataMessage looks like this for example: dataMessage={15,1,9400000}
Well in my buffer I would expect this Byte sequence "\x06\xF0\x01\x00\x8F\6E\xC0"
but I always get the following Output "\x06\xF0\x01\x00\x8Fn\xC0".
What am I doing wrong?

Related

how to transfer QImage from QLocalServer to QLocalSocket

I have two mac apps that communicate with each other using QLocalSocket.
Able to send the received QString but not able to send the received QImage Below is my code.
SERVER SIDE CODE
QImage image(":/asset/logo_active.png");
QByteArray ba;
qDebug() << image.sizeInBytes() <<image.size();
ba.append((char *)image.bits(),image.sizeInBytes());
qDebug() <<ba.size(); //262144
this->mSocket->write(ba);
if(!this->mSocket->waitForBytesWritten(-1))
{
qDebug() << "writen Bytes error " << this->mSocket->errorString();
}
this->mSocket->flush();
CLIENT SIDE CODE
connect(mLocalSocket,&QLocalSocket::readyRead, [&]() {
QByteArray ba;
ba = mLocalSocket->readAll();
qDebug() << "size is" << ba.size(); // size is 0
QImage image((uchar *)ba.data(),1024,768,QImage::Format_RGB32);
ui->labelStream->setPixmap(QPixmap::fromImage(img));
});
at sender 262144 is the byte-array size
but at the receiver, byte-array size is 0
Do let me know if I am missing anything.
Thanks In Advance
Finally I got the solutions I used QDataStream below is the code example.
SERVER SIDE CODE:
QDataStream T(mSocket);
T.setVersion(QDataStream::Qt_5_7);
QByteArray ba;
ba.append((char *)img.bits(),img.sizeInBytes());
T << ba;
mSocket->flush();
CLIENT SIDE CODE
QByteArray jsonData;
QDataStream socketStream(mLocalSocket);
socketStream.setVersion(QDataStream::Qt_5_7);
for (;;) {
socketStream.startTransaction();
socketStream >> jsonData;
if (socketStream.commitTransaction()) {
QImage image((uchar *)jsonData.data(),640,480,QImage::Format_RGB888);
ui->labelStream->setPixmap(QPixmap::fromImage(image));
}else {
// the read failed, the socket goes automatically back to the state it was in before the transaction started
// we just exit the loop and wait for more data to become available
break;
}
}
Thanks, Everyone for your support also Stackoverflow.

How to get datas send by Protobuf with a QTcpSocket [duplicate]

This question already has answers here:
Correct way to losslessly convert to and from std::string and QByteArray
(3 answers)
Closed 3 years ago.
I'm new on protobuf and QTcpServer/Socket and I want to read my .proto data send by my client, but when i'm reading the data, the QString done is empty
For now, I just want to send a message that say "hello" when my client is connected. The QByteArray returning by QTcpSocket::readAll is NOT empty, but the QString created with the bytes is empty.
Here is my .proto ultra basic one :
syntax = "proto3";
package protobuf;
message Message
{
string content = 2;
}
write functions :
// When i'm connecting to the server i create a PlayerManager and i call this function with message = "hello"
void Server::sendMessageToPlayer(const PlayerManager& playerManager, const QString& message)
{
auto messageProto = new protobuf::Message;
messageProto->set_content(message.toStdString());
playerManager.socketManager()->sendData(*messageProto);
}
// I serialize the protobuf
template <typename protobufType>
void sendData(const protobufType& protobuf)
{
std::string dataToSend;
if (!protobuf.SerializeToString(&dataToSend))
{
// This never pass -> the protobuf is well serialize
qDebug() << "The protobuf send cannot be serialized, please, make sure that you used protobufs correctly";
}
// Before i write it
write(dataToSend);
}
void SocketManager::write(const std::string& data)
{
// I tried this but it's not working either
// QTextCodec* codec = QTextCodec::codecForName("CP1251");
// QString codecData = codec->toUnicode(data.c_str());
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_10);
out << data.c_str();
_tcpSocket->write(block);
qDebug() << block;
}
read functions :
void SocketManager::read()
{
QByteArray bytes = _tcpSocket->readAll();
qDebug() << bytes;
// Doesn't work either
// QTextCodec* codec = QTextCodec::codecForName("CP1251");
// QString data = codec->toUnicode(bytes);
QString data(bytes);
qDebug() << data;
emitMessageType(data.toStdString());
}
void SocketManager::emitMessageType(const std::string& data)
{
// Protobufs can parse an empty string (and so, emit signal), to avoid that, the function will tell you if data
// are empty, then return
if (data.empty())
{
qDebug() << "Datas are empty";
return;
}
protobuf::Message message;
if (message.ParseFromString(data))
{
emit messageProtoReceived(message);
return;
}
qDebug() << "The data send cannot be translate, please, make sure that you used protobufs correctly";
}
So, I would like that my client receive "hello" when he is connected but my debug are :
Server side :
"\x00\x00\x00\b\x12\x05hello\x00"
Client side
"\x00\x00\x00\b\x12\x05hello\x00"
""
Datas are empty
When I use QTextCodec (commented lines of the code) the debug are :
Server side :
"\x00\x00\x00\x0E\x00\x12\x00\x05\x00h\x00""e\x00l\x00l\x00o"
Client side
"\x00\x00\x00\x0E\x00\x12\x00\x05\x00h\x00""e\x00l\x00l\x00o"
"\u0000\u0000\u0000\u000E\u0000\u0012\u0000\u0005\u0000h\u0000e\u0000l\u0000l\u0000o"
The data send cannot be translate, please, make sure that you used protobufs correctly
So the QByteArea is parse, but protobuf don't succeed to parse the given string.
Thanks for reading, I hope youc ould help me
Not sure if it's the case but the documentation says that the default constructor of a QString that takes a QByteArray:
The given byte array is converted to Unicode using fromUtf8(). Stops copying at the first 0 character, otherwise copies the entire byte array.
So probably, you are having some troubles whit the conversion.
As alternative, you can try ParseFromArray method, instead of converting a QByteArray into a std::string.
const auto byteArray = _tcpSocket->readAll();
protobuf::Message message;
if (!message.ParseFromArray(byteArray.data(), byteArray.size())) {
qDebug() << "Failed to parse person.pb.";
}
out << data.c_str() inside SocketManager::write might discard at first \0. Try converting to QByteArray as described at Correct way to losslessly convert to and from std::string and QByteArray to ensure the whole string is sent.

toLocal8bit send over TCP

Im creating TCP Server/Client application in QT Creator framework. I want to get some data from UI input field and send it over TCP.
Im doing something like this in client application:
void MainWindow::on_btn_login_clicked()
{
QByteArray text = (ui->login_input->text()).toLocal8Bit();
char* out = text.data();
connection->ConnectAndSendData(out);
}
and in the ConnectAndSendData function:
void TcpConnect::ConnectAndSendData(const char* data)
{
socket = new QTcpSocket(this);
int port = 1234;
socket->connectToHost("localhost", port);
if(socket->waitForConnected(3000))
{
qDebug() << "connected to s. localhost at port " << port;
socket->flush();
socket->write(data, sizeof(data));
qDebug() << data << "\n";
socket->waitForReadyRead();
char* serverresponse;
socket->read(serverresponse, 128);
if(serverresponse == MESSAGE_LOGINRQ)
socket->write(data);
socket->flush();
socket->close();
}
else
{
/**/
}
}
and the data in line socket->write(data, sizeof(data)); is properly send to server, but when server echoes it, it looks like "something/x00/x00/x00/x00" or somethinglike that. Also when i to do something like this:
#define MESSAGE_WANTLOGIN "wanlogin"
socket->write(MESSAGE_WANTLOGIN, sizeof(MESSAGE_WANTLOGIN));
message is messed up with those null signs.
on the server side receiving data look as simple as:
void Thread::readyRead()
{
socket->flush();
QByteArray data = socket->readAll();
qDebug() << "data received: " << data;
if(data == MESSAGE_WANTLOGIN)
{
socket->write(MESSAGE_LOGINRQ);
} else
{
qDebug() << "error not messageloginrq";
}
}
and like u can assume, though i send "wanlogin" message, server receiving something like "wanlogin/x00/x00" and this if obviously returns false.
this trash is applied on the end of data, and this impossible to check what message was send. The other thing is that maximum size of send data is 8 chars, but also to data of this length trash is applied so it looks like "wanlogin/x00/x00"; however, when i type more chars, for example 10, the send data is just cut to 8 signs, with no /x00s.
So my question is how to clear data from those /x00s and how to send more than 1 byte of information(i need it e.g. to send login and password of user). Sorry if there's some stupid mistake, its my first client/server application which also using multithreading for each client.
sizeof(data) is 4 or 8 depending if you are on a 32-bit or 64-bit machine. It is not the size of your data, but the size (in byte) of a pointer.
So what happens is that your actual wanlogin is in fact a 6 character string, and you end up sending 2 more bytes. In this case you are lucky: the char array returned by data() is null-terminated, so you have one extra 0 that you can access, but accessing the second 0 is undefined behavior i.e anything can happen.
The solution is to use strlen() instead of sizeof. Or, better, to directly call write() with a QByteArray by changing ConnectAndSendData(const char* data) to ConnectAndSendData(const QByteArray &data).
void MainWindow::on_btn_login_clicked()
{
const QByteArray text = (ui->login_input->text()).toLocal8Bit();
connection->ConnectAndSendData(text);
}
void TcpConnect::ConnectAndSendData(const QByteArray & data)
{
socket = new QTcpSocket(this);
quint16 port = 1234;
socket->connectToHost("localhost", port);
if(socket->waitForConnected(3000))
{
qDebug() << "connected to s. localhost at port " << port;
socket->write(data);
...
}
...
}

How to read data from the serial port in QT?

I am creating a script in QT for reading the format packages (AA), (BB), etc from serial port. I open the serial port, but when I go to check inside the QByteArray values, comes back that I could not read any value.
This is my code
...
QSerialPort *serialPort = new QSerialPort();
serialPort->setPortName("ttyUSB0");
serialPort->setParity(QSerialPort::NoParity);
serialPort->setBaudRate(QSerialPort::Baud9600, QSerialPort::AllDirections);
serialPort->setStopBits(QSerialPort::OneStop);
serialPort->setFlowControl(QSerialPort::NoFlowControl);
serialPort->open(QIODevice::ReadOnly);
if (serialPort->isOpen()) {
qDebug() << "Serial port is open...";
QByteArray datas = serialPort->readAll();
if (datas.size() == 0) {
qDebug() << "Arrived data: 0";
} else {
for (int i = 0; i < datas.size(); i++){
if (datas.at(i)) {
qDebug() << datas[i];
}
}
}
} else {
qDebug() << "OPEN ERROR: " << serialPort->errorString();
}
serialPort->close();
qDebug() << "...serial port is closed!";
return 0;
...
You called readAll() immediately after open(). It probably took the computer a few nanoseconds to get from one to the other.
At 9600 baud, each byte of data takes slightly more than one millisecond to transfer. It would be absolutely impossible for any data to have arrived in that short an interval, so that's why you got no data.
Serial ports don't begin buffering incoming data until you open them (how could they, what baud rate and other settings would be used for receiving and buffering when no program has the port open?)
Use either a blocking read function of some sort (such as readLine()) or an event loop that reacts to data when it arrives.

copying char to QbyteArray with datastream contains some extra bytes

Overview of problem:
OS : Ubuntu
I am using qt utility to receive video data from remote machine( remote machine is using gstreamer to send live data) and write that data to port say 5000.
Port 5000 is already bind to another gstreamer utility. this utility listen to port 5000 and convert data into video streaming. Obviously things are not exactly working and I cant view video. So I have two questions:
1) With Qt utility , is it legal to write to port 5000 although port is bind to gstreamer utility.
2) I am using 3rd party library and its api to receive data from external source. The data get stored in array of characters. If I convert that into qbytearray then qbytearray has same size as char buffer. example
rc = zco_receive_source(sdr, &reader, bytesToRead, buffer); // this is 3rd part function
qDebug() << " copy buffer size =" << rc; // genrally this size is 1412
QByteArray msgRecvd;
msgRecvd = QByteArray(reinterpret_cast<char*>(buffer), rc);
if(! msgRecvd.isEmpty() )
{
qDebug() << " size of msgRecv =" << msgRecvd.size();// again 1412
udpSock->writeDatagram( msgRecvd, QHostAddress::LocalHost, 5000 );
}
But if I use QDataStream then QbyteArray got 4 extra bytes. code shown below
rc = zco_receive_source(sdr, &reader, bytesToRead, buffer); // this is 3rd part function
qDebug() << " copy buffer size =" << rc; // genrally this size is 1412
QByteArray msgRecvd;
QDataStream dataStream( &msgRecvd, QIODevice::WriteOnly );
dataStream.writeBytes( ( const char* )buffer, rc );
if(! msgRecvd.isEmpty() )
{
qDebug() << " size of msgRecv =" << msgRecvd.size();// got 4 extra bytes .. size is 1415. why ???
udpSock->writeDatagram( msgRecvd, QHostAddress::LocalHost, 5000 );
}
I want to know why QbyteArray got extra character and do I need to serialise data to forward it to port 5000?
Answering on second question:
Try QDataStream::writeRawData().
Form Qt docs:
QDataStream & QDataStream::writeBytes(const char * s, uint len)
Writes the length specifier len and the buffer s to the stream and returns a reference to the stream.
The len is serialized as a quint32, followed by len bytes from s. Note that the data is not encoded.