Why QTcpSocket received wrong data? - c++

I'm writing a simple network application. Client sending to server message server printing it in QTextEdit and responding to client .
I'm using QTcpServer and QTcpSocket.
There is a problem I can't solve. Receiving data is quint16 + QTime + QString which is sending as QByteArrey.
I use quint16 for receiving size of data blocks. And for some reason when client send to server
next block size: 16 (quint16 value)
block size: 18
Server get:
next block size: 30073 (quint16 value)
block size: 18
As you can see, for some reason server getting from QDataStrem wrong variable value and it is always 30073. I don't understand why?
void Widget::slotSendToServer()
{
logTextEdit->append("slotSendToServer()");
QByteArray arrBlock;
QDataStream serverSendStream(&arrBlock, QIODevice::ReadWrite);
QString messageStr = messageLineEdit->text();
serverSendStream << quint16(0) << QTime::currentTime()
<< messageStr;
serverSendStream.device()->seek(0);
serverSendStream << (quint16)(arrBlock.size() - sizeof(quint16));
qDebug() << "next_block_size:"
<<(quint16)(arrBlock.size() - sizeof(quint16))
<< endl
<< "full size of Byte arrey:" << arrBlock.size();
tcpSocket->write(arrBlock);
messageLineEdit->clear();
}
void Widget::slotReadClient()
{
logTextEdit->append("slotReadClient()");
QTcpSocket *tcpSocket = (QTcpSocket*)sender();
QDataStream clientReadStream(tcpSocket);
while(true)
{
if (!next_block_size)
{
if (tcpSocket->bytesAvailable() < sizeof(quint16))
{
break;
}
clientReadStream >> next_block_size;
}
if (tcpSocket->bytesAvailable() < next_block_size)
{
break;
}
QTime time;
QString messageTextStr;
clientReadStream >> time >> messageTextStr;
QString messageCompleteStr =
time.toString() + " " + "Client has sent - "
+ messageTextStr;
logTextEdit->append("Message received: ");
logTextEdit->append(messageCompleteStr);
next_block_size = 0;
sendToClient(tcpSocket,
"Server Response: Received \""
+ messageTextStr + "\"");
}
}

You should ensure that the variable next_block_size is initialized to 0 each time the socket is connected.
If you don't reuse the same QTcpSocket object, this can be done in your Widget class constructor, or if you do, in a slot connected to signal connected().

I have no idea why you did it it so complicated.
This should work:
void Widget::slotSendToServer()
{
logTextEdit->append("slotSendToServer()");
QByteArray arrBlock;
QDataStream serverSendStream(tcpSocket);
serverSendStream << QTime::currentTime()
<< messageLineEdit->text();
messageLineEdit->clear();
}
void Widget::slotReadClient()
{
logTextEdit->append("slotReadClient()");
QTcpSocket *tcpSocket = (QTcpSocket*)sender();
QDataStream clientReadStream(tcpSocket);
QTime time;
QString message;
clientReadStream >> time >> message;
emit YourSignal(time, message);
}
You don't have to worry about sizes, QDataStream keep track of it, you only have to maintain same sequence of read as it was done on write, so your buffer arrBlock is waste of code.
According to documentation my code should block when not all data are available at the moment of reading and this is only disadvantage. For small data like date and some string it will never happen.
About your code, you have messed up your reader with while loop for sure, so here is correction without this loop.
void Widget::slotReadClient()
{
logTextEdit->append("slotReadClient()");
QTcpSocket *tcpSocket = (QTcpSocket*)sender();
QDataStream clientReadStream(tcpSocket);
if (next_block_size==0) {
// need to read data size
if (tcpSocket->bytesAvailable() < sizeof(quint16))
return; // wait for next signal
// next_block_size must be type of qint16
clientReadStream >> next_block_size;
}
if (tcpSocket->bytesAvailable() < next_block_size) {
// not enought data to complete read immediately
return; // wait for next signal
}
QTime time;
QString messageTextStr;
clientReadStream >> time >> messageTextStr;
QString messageCompleteStr =
time.toString() + " " + "Client has sent - "
+ messageTextStr;
logTextEdit->append("Message received: ");
logTextEdit->append(messageCompleteStr);
// mark that data read has been finished
next_block_size = 0;
}

Related

Decoding data from serial port (string with integers)

I'm sending string from Arduino to PC using serial communication. Format of message includes char, value and space (separating data). Example message: "H123 V2 L63 V2413 I23 CRC2a".
I have problem with decoding this message in Qt because when I use for example Utf-8 decoding it casting integers to chars (in a simplified way) and I receiving something like that: "H&?? j\u0002I&\u001AICL?H". Message length is not constant (different size for ex. H12 and H123) so I can't use predetermined position to casting. Do you have any idea how to decode message correctly?
Arduino code:
uint8_t H = 0, V = 0, L = 0, I = 0, CRC = 0;
String data;
void loop() {
++H; ++V; ++L; ++I;
data = String("H");
data += String(H, DEC);
data += String(" V");
data += String(V, DEC);
data += String(" L");
data += String(L, DEC);
data += String(" I");
data += String(I, DEC);
CRC = CRC8(data.c_str(), strlen(data.c_str()));
data += String(" CRC");
data += String(CRC, HEX);
Serial.println(data);
delay(1000);
}
Qt code:
while(serial.isOpen())
{
QByteArray data;
if (serial.waitForReadyRead(1000))
{
data = serial.readLine();
while (serial.waitForReadyRead(100))
{
data += serial.readAll();
}
QString response = QString::fromUtf8(data);
qDebug() << "Data " << response << endl;
}
else
qDebug() << "Timeout";
}
The problem is that you use UTF-8 decoding, while Arduino send just 1-byte ASCII chars. So use fromLocal8Bit as said albert828
Like this:
while(serial.isOpen())
{
QByteArray data;
if (serial.waitForReadyRead(1000))
{
data = serial.readLine();
while (serial.waitForReadyRead(100))
{
data += serial.readAll();
}
QString response = QString::fromLocal8Bit(data);
qDebug() << "Data " << response << endl;
}
else
qDebug() << "Timeout";
}

Qt: Using QTcpSocket -> I can write on socket, but I can't read...

I am using Qt 4.8 GCC 32bit on xUbuntu 14.04.
I have the following piece of code, a TCP server that I use in order to get some remote commands and send back some answers - via TCP socket:
struct _MyRequest
{
unsigned long Request;
unsigned long Data;
} __attribute__((packed));
struct _MyAnswer
{
unsigned long Error;
unsigned long Filler;
} __attribute__((packed));
_MyRequest request;
_MyAnswer answer;
RemoteCmdServer::RemoteCmdServer(QObject * parent)
: QTcpServer(parent)
{
qDebug() << "Server started";
listen(QHostAddress("172.31.250.110"), 5004);
connect(this, SIGNAL(newConnection()), this, SLOT(processPendingRequest()));
}
void RemoteCmdServer::processPendingRequest()
{
qDebug() << "Process request";
QTcpSocket * clientConnection = nextPendingConnection();
connect(clientConnection, SIGNAL(disconnected()), clientConnection, SLOT(deleteLater()));
// get the request
int ret = clientConnection->read((char*)&request, sizeof(request));
qDebug() << "READ: " << ret;
if(ret == sizeof(request))
{
// send answer
clientConnection->write((char*)&answer, sizeof(answer));
}
qDebug() << "Disconnecting...";
clientConnection->disconnectFromHost();
}
I am able to write correctly if I comment the if(ret == sizeof(request)) line.
Yet, I can't read from the socket (I always get 0 bytes).
I am 100% sure that the TCP-tool I use to send packets to my app works ok.
Here is the debug output from my app:
Server started
Process request
READ: 0
Disconnecting...
What am I doing wrong? Please advise!
You should wait for the data either in a non-blocking or blocking way. You can use waitForReadyRead to do it in a blocking way.
void RemoteCmdServer::processPendingRequest()
{
qDebug() << "Process request";
QTcpSocket * clientConnection = nextPendingConnection();
connect(clientConnection, SIGNAL(disconnected()), clientConnection, SLOT(deleteLater()));
if (clientConnection->waitForReadyRead())
{
// get the request
QByteArray message = clientConnection->readAll(); // Read message
qDebug() << "Message:" << QString(message);
}
else
{
qDebug().nospace() << "ERROR: could not receive message (" << qPrintable(clientConnection->errorString()) << ")";
}
qDebug() << "Disconnecting...";
clientConnection->disconnectFromHost();
}
You're trying to read data from the new connection without returning to the Qt event loop -- I don't think that's going to work.
After you've accepted the connect with...
QTcpSocket * clientConnection = nextPendingConnection();
You need to connect to its readyRead signal with something like...
connect(clientConnection, SIGNAL(readyRead()), this, SLOT(my_read_slot()));
Where my_read_slot is the member function that will actually perform the read operation.

QUdpSocket Multicastreceiver

I an writing a Programm in Qt which should discover Routers in a LAN via UPnP.
This is the constructor of my class:
Discovery::Discovery(QObject *parent):QObject(parent)
{
groupAddress = QHostAddress("239.255.255.250");
ssdpPort = 1900;
socket = new QUdpSocket(this);
socket->joinMulticastGroup(groupAddress);
connect(socket,SIGNAL(readyRead()),this,SLOT(processPendingDatagrams()));
discovered = new QList<DiscoveryMatch>();
}
After creating, I send out the search message:
void Discovery::discover()
{
QByteArray Data;
Data.append("M-SEARCH * HTTP/1.1\r\n");
Data.append("HOST: 239.255.255.250:1900\r\n");
Data.append("ST: urn:schemas-upnp-org:device:InternetGatewayDevice:1\r\n");
Data.append("MAN: \"ssdp:discover\"\r\n");
Data.append("MX: 5\r\n\r\n");
socket->writeDatagram(Data, groupAddress, ssdpPort);
}
If a device answered, I process the reply with the readyRead() Signal:
void Discovery::processPendingDatagrams()
{
QByteArray buffer;
QHostAddress sender;
quint16 senderPort;
while(socket->hasPendingDatagrams())
{
buffer.resize(socket->pendingDatagramSize());
socket->readDatagram(buffer.data(), buffer.size(),&sender, &senderPort);
qDebug() << "Message from: " << sender.toString();
qDebug() << "Message port: " << senderPort;
qDebug() << "Message " << buffer;
processDatagram(buffer);
}
}
I have 2 Routers in my Network and if I run the Programm the socket reads the Datagram from my DrayTek Router and ignores the response from my FRITZ!Box.
The strange thing is, that if I run the Programm in Debug mode the socket catches both responses as I intended.
Is this a Qt Problem or do I something wrong?
Thank you for reading and for any advise.

Boost asynchronous read and write weird data from streambuffer

I'm using boost to asynchronously read and write to my microcontroller. I have my microcontroller rigged so that it reads the data sent by the asynchronous write and echoes it back to the computer, where the computer reads it via an asynchronous read on a single thread. I'm sending over "15" to the microcontroller. Every first send after plugging the microcontroller in it works well, but after this it will sporadically "read" from the serial port "f" and "?f15". Whenever f or ?f15 is sent over, 7 bytes are transferred in the callback, which makes very little sense to me, since f is just a single ascii value. Here is my clientside Serial port wrapper code:
void Serial::async_write(std::string string){
std::cout << "String size:" << string.size() << std::endl;
// char stringToChar[string.size() + 1];
// strcpy(stringToChar, string.c_str());
// this->async_write(stringToChar);
boost::asio::async_write(*port_, boost::asio::buffer(string, string.length()), boost::bind(&Serial::async_write_handler, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
void Serial::async_write_buffer(std::vector<char> data){
int num = data.size();
std::cout << num << std::endl;
boost::asio::mutable_buffer buf(&data, data.size());
boost::asio::async_write(*port_, boost::asio::buffer(data, data.size()), boost::bind(&Serial::async_write_handler, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
void Serial::async_write_handler(const boost::system::error_code &e, std::size_t bytes_written){
std::cout << "Data written" << std::endl;
//b_->consume(bytes_written);
}
void Serial::async_read_handler(const boost::system::error_code &e, std::size_t bytes_read){
if(!(*e)){
std::cout << "bytes read in async read handler:" << bytes_read << std::endl;
if(bytes_read > 0){
b_->commit(bytes_read);
std::istream* instream = new std::istream(b_);
std::string streamtostring;
*instream >> streamtostring;
std::cout << "size of input buffer:" << b_->size() << std::endl;
std::cout << "Read: " <<std::endl;
b_->consume(bytes_read);
std::cout << streamtostring << std::endl;
}
else{
std::cout << "No bytes read" << std::endl;
}
}
else{
std::cout << "Error occurred!" << std::endl;
std::cerr << e.message() << std::endl;
}
}
void Serial::async_read_until(std::string delim){
boost::system::error_code e;
boost::asio::async_read_until(*port_, *b_, delim, boost::bind(&Serial::async_read_handler, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
and here is the code that calls it in main.cpp:
int main(){
boost::asio::io_service io;
Serial::Serial serial(PORT, &io, 9600);
if(!serial.is_open()){
serial.open(PORT);
}
std::string s = "15";
serial.async_write(s);
serial.async_read_until("\n");
// const char arr[] = {'2', '5', '5'};
// serial.async_write(arr);
// std::string s = "50089q503320232500202";
// std::vector<char> data(s.begin(), s.end());
// serial.async_write_buffer(data);
io.run();
}
Now on the microcontroller side, I have it place each of the incoming data bytes into a stackArray of chars, where they are then popped out one by one into a char array that is 1 more character long than that of the stack array. Since the asynchronous read reads until a newline, I insert a newline at the very end of the character array. I then send it off across the stream.
#include <StackArray.h>
StackArray<int> binary;
int ledPin = 13;
int numberOfExecs = 0;
byte data = 0;
void setup() {
Serial.begin(9600);
//binary.setPrinter(Serial);
pinMode(ledPin, OUTPUT);
}
void blink(int times, int duration){
for(int i = 0; i < times; i++){
digitalWrite(ledPin, HIGH);
delay(duration);
digitalWrite(ledPin, LOW);
delay(duration);
}
}
void loop() {
//get number of bytes waiting in the serial buffer
int bytesWaiting = Serial.available();
//create array of character values
StackArray<char> letterVals;
//Set the printer for the stack array to serial
letterVals.setPrinter(Serial);
//while serial is available, push each byte of data to the stack array
while(Serial.available() > 0){
byte data = Serial.read();
char c = data;
//Serial.println(c);
letterVals.push(c);
// convertToBinary(data, binary);
// printToLED(binary);
}
//Get the number of elements in the stack array
int numElements = letterVals.count();
//indicate how many elements there are on the led
blink(numElements, 1000);
// blink(1, 5000);
//length of array
int len = numElements + 1;
//create array to send back data
char sendback[len];
if(bytesWaiting > 0){
for(int i = len - 2; i >= 0; i--){
//pop each character into its original position
int asciiVal = letterVals.pop();
//blink(asciiVal, 350);
//blink(20, 20);
sendback[i] = asciiVal;
}
}
//set last character to newline
sendback[len - 1] = 10;
//if there are no bytes available to read, send off data
if(bytesWaiting > 0){
Serial.println(sendback);
}
}
Does anyone know why random f's and ?f's keep appearing? Thanks.
This may be the result of the client code invoking undefined behavior. Specifically, the code fails to meet a lifetime requirement for boost::asio::async_write()'s buffers parameter:
[...] ownership of the underlying memory blocks is retained by the caller, which must guarantee that they remain valid until the handler is called.
In both Serial::async_write() and Serial::async_write_buffer(), the underlying memory provided as the buffer is owned by an object whose lifetime ends once the function returns. As neither of these functions makes no guarantee that they will not return until async_write's completion handler has been invoked, the lifetime of the temporary violates a requirement of async_write(), resulting in in undefined behavior.
void Serial::async_write(std::string string)
{
boost::asio::async_write(
...,
boost::asio::buffer(string, string.length()),
...);
} // `string`'s lifetime ends.
void Serial::async_write_buffer(std::vector<char> data)
{
boost::asio::async_write(
...,
boost::asio::buffer(data, data.size()),
...);
} // `data`'s lifetime ends.

How to implement a simple tcp connection in Qt?

I tried to modify the Qt network tutorial, and implemented it like:
quint16 blockSize;
void Client::readData()
{
qDebug() << "Received Data!";
QByteArray data;
QDataStream in(tcpSocket);
in.setVersion(QDataStream::Qt_4_0);
if (blockSize == 0) {
if (tcpSocket->bytesAvailable() < (int)sizeof(quint16))
return;
in >> blockSize;
}
qDebug() << "Received DATA II with blocksize " << blockSize;
if (tcpSocket->bytesAvailable() < blockSize)
{
qDebug() << tcpSocket->bytesAvailable() << ' ' << blockSize;
return;
}
qDebug() << "Received DATA III";
in >> data;
qDebug() << data;
QByteArray dbg = data; // create a copy to not alter the buffer itself
dbg.replace('\\', "\\\\"); // escape the backslash itself
dbg.replace('\0', "\\0"); // get rid of 0 characters
dbg.replace('\n', "\\n");
//dbg.replace('"', "\\\""); // more special characters as you like
qDebug() << dbg;
QString data_string(data);
qDebug() << "Emitting Signal";
emit Client::gotData(data_string);
}
void Server::sendData(void)
{
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_0);
out << (quint16)0;
out << "Hello World, this is a very long text!";
out.device()->seek(0);
out << (quint16)(block.size() - sizeof(quint16));
qDebug() << "First number is: " << (quint16)(block.size() - sizeof(quint16));
qDebug() << "Blocksize is: " << block.size() << "with quint size: " << sizeof(quint16);
qDebug() << "Sending data!";
//Debug
QByteArray dbg = block; // create a copy to not alter the buffer itself
dbg.replace('\\', "\\\\"); // escape the backslash itself
dbg.replace('\0', "\\0"); // get rid of 0 characters
dbg.replace('\n', "\\n");
//dbg.replace('"', "\\\""); // more special characters as you like
qDebug() << dbg;
connect(clientConnection, SIGNAL(disconnected()), clientConnection, SLOT(deleteLater()));
clientConnection->write(block);
//clientConnection->disconnectFromHost();
}
Connecting works fine, but when I call sendData(), I get (from the same function) the transmitted block:
First number is: 43
Blocksize is: 45 with quint size: 2
Sending data!
"\0+\0\0\0'Hello World, this is a very long text!\0"
My first problem is: Where do all the \0 come from? As far as I understand the code, first I'm creating a 0, then I write the text, and them I am going back to the front and write the full size of the block. Is it because of the size of the (quint16)? When entering nothing, I get \0\0 and a size of 0, which is correct. The size of the example above is 43, which corresponds to + in ascii (and this sign is in the block above, too).
My second problem is: My readData()-function does not recognize the block size, (it always returns 450 as block size, which is clearly wrong). Why? Did I miss something?
UPDATE: After changing QByteArray data; to QString data; my problems are gone, no more strange \0 in my code -> should have used the right data type -> Head->Desk