copying char to QbyteArray with datastream contains some extra bytes - c++

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.

Related

Sending hex data via serial communication with QT

I am finding way to send hex data via serial communication
i searched it several times and followed some ways but it didn't work.
i checked that protocol is working with using other software that sending hex data to device
below is my code
const char data[]={0xAA,0xAA,0x01,0x00,0x00,0x0E,0x00,0x01,0x00,0x00,0x00,0x2D,0x37,0x1D,0xAA,0xAA,0x01,0x00,0x00,0x0E,0x00,0x0C,0x10,0x00,0x00,0x01,0x76,0x13};
serial->setPortName(("COM8"));
initSerialPort(); // baud rate and etc
if(serial->open(QIODevice::ReadWrite))
{
qDebug()<<"Port is open!";
if(serial->isWritable())
{
qDebug()<<"Yes, i can write to port!";
int size = sizeof(data);
serial->write(data,size);
}
}
and when i use other declare like uint16_t, uchar, write function cannot convert argument 1 from uint16_t (or uchar) to const char *
i did try also this form
QByteArray hex("AAAA0100000E00010000002D371DAAAA0100000E000C100000017613");
QByteArray data = QByteArray::fromHex(hex);
and it also didnt work
You can do this using only QByteArray like:
connect(serial, &QSerialPort::readyRead, this, &YourClass::doSomeStuff);
QByteArray arr;
arr += static_cast<char>(0xAA);
arr += static_cast<char>(0x01);
<...>
serial->setPortName("COM8");
initSerialPort(); // baud rate and etc
if(serial->open(QIODevice::ReadWrite) && serial->isWritable())
serial->write(arr);

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);
...
}
...
}

qt c++ send 6 bytes using tcp protocol

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?

C++ Windows RPC how to define the MIDL can transmit null terminated char array

My project is use C++ Windows RPC to upload image(512*512) from client to server. I do not use WIN RPC before, So I tried some examples include send basic "Hello world" Message to server, but the huge issue is the function can't send unsigned char* include '\0'. I mean there are a lot of '\0' characters in the char array, they can't send to the server.
I think it is because I defined wrong MIDL function.
I tried:
void Output(
[in, out, size_is(1048576), string] unsigned char* szString);
another one
void Output1(
[in, length_is(1048576)] unsigned char[]);
But both can't work.
I use opencv3.2 to read image to Mat structure, and it can get Mat data and use memcpy to copy the Mat.data then create a new image in local client. But when I send Mat.data to server, the first of characters in the Mat.data is '\0'. All the Mat.data can't send to server.
My Client core code(It has include all require header) is
Mat I = imread("U:\\normal.jpg", IMREAD_ANYDEPTH);
if (I.empty())
{
std::cout << "!!! Failed imread(): image not found" << std::endl;
// don't let the execution continue, else imshow() will crash.
}
if (!I.data) {
std::cout << "can't open or find image" << std::endl;
//return -1;
}
I.convertTo(I, CV_32F);
I = (I.reshape(0, 1)); // to make it continuous
char tr[512*512*4];
memcpy_s(tr, 512 * 512 * 4, I.data, 512*512 * 4);
//snprintf(tr, 512*512*4,"%s", I.data);
Mat out = Mat(512,512, CV_32F, &tr[0]);
namedWindow("Display window", CV_WINDOW_AUTOSIZE);// Create a window for display.
imshow("Display window", out);
waitKey(5000);
...
RpcTryExcept
{
std::clog << "Calling Open" << std::endl;
output((unsigned char* )tr); // process the function, send data to server
//output1((unsigned char* )tr);
}

Determine Data Type on a TCP Socket in Qt

I am writing a program to send images captured from an OpenCV window over a TCP connection, using Qt libraries to setup the connections etc.
I have to functions (below) which are both working to send either text or a byte array. The problem I have is at the other end how can I tell if the data coming in is plain text, or an array containing an image. Is there an inbuilt way to do this, or do I need to put a byte at the start of the data to tell the receiver what data is coming? I already put the array length at the start of the serialized image data.
void Screenshot_controller::sendText(std::string textToSend)
{
if(connectionMade)
{
std::string endLine = "\r\n";
textToSend = textToSend + endLine;
const char * textChar = textToSend.c_str();
sendSocket->write(textChar);
sendSocket->flush();
qDebug() << "Text Sent from Server";
}
}
void Screenshot_controller::sendData(QByteArray dataToSend)
{
if(connectionMade)
{
sendSocket->write(dataToSend);
sendSocket->flush();
qDebug() << "Data Sent from Server";
}
}
You need to define the protocol yourself, whether that's with a byte, string, JSON header or any other method. The Tcp socket will allow you to transfer the data, but doesn't care what that data is; it's up to you to handle that.