PDA

View Full Version : transfer struct data on udpSocket



malone
17th January 2019, 12:28
hello community,

i am new in this forum and in qt I need your help to finish my program.
i am writing a c++ code with the IDE Qt for my project.
i have two separately classes, that communicate on updsocket. One class(SendObjects) send data on port 50885 and the second class(receiveObjects) receive this data on port 50885. The data to send are of type struct. In both classes i have declared a structure type, called mDataChannels with 6 elements: Channel_Nr, AC_Volt, DC_Volt,etc...
Now on my socket with port 50885 from class "SendObjects", i want to send simultaneously 40 objects of typ structure(mDataChannels) and then receive this all objects(or all elements of this) on the other class names "receiveObjects".
i tried to write a code with and without QVector but it doesn't work fine. I need help to improve my code. i don't have error but i cannot read something. I don't too know if my class "SendObjects" or my class "receiveObjects" really work fine. I have added a new QDataStream Operator. may be it is wrong.

SendObject.h


#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QUdpSocket>
#include <QTimer>
#include <QDateTime>
#include <vector>
#include <QString>
#include <QDebug>
#include <QVector>

namespace Ui {
class MainWindow;
}

struct mDataChannels
{
QString mmyChannel_Nr;
float mAC_Volt;
float mDC_Volt;
float mAC_Current;
float mDC_Current;
float mmPotential;
};

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();

friend QDataStream& operator << (QDataStream &stream, const QVector<mDataChannels> &_DataTest);

private slots:
void sendTestData();

private:
Ui::MainWindow *ui;
QUdpSocket *testUdpSocket;
QTimer *testTimer;
QVector < mDataChannels > _DataTest, temp;
};

#endif // MAINWINDOW_H
,

SendObject.cpp



#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
testUdpSocket = new QUdpSocket(this);
_DataTest.resize(40);
temp.resize(40);
for(int i = 0; i < 40; i++)
{
_DataTest[i].mmyChannel_Nr = tr("Kanal ") +QString::number(i + 1);
_DataTest[i].mAC_Volt = 150.320 + (float)i;
_DataTest[i].mDC_Volt = 80.67 + (float)i;
_DataTest[i].mAC_Current = 5.0 + (float)i/10;
_DataTest[i].mDC_Current = 3.0 + (float)i/10;
_DataTest[i].mmPotential = 6.0 + (float)i/2;
}


testTimer = new QTimer(this);
connect(testTimer, SIGNAL(timeout()), this, SLOT(sendTestData()));
testTimer->start(2 * 1000);


}

MainWindow::~MainWindow()
{
delete ui;
}


QDataStream& operator << (QDataStream &stream, QVector<mDataChannels> &_DataTest)
{
_DataTest.resize(40);
QDateTime dataTime;
stream << dataTime;
for(int i = 0; i < 40; i++)
stream << (QString)_DataTest[i].mmyChannel_Nr << static_cast<float>(_DataTest[i].mAC_Volt)
<< static_cast<float>(_DataTest[i].mDC_Volt) << static_cast<float>(_DataTest[i].mAC_Current)
<< static_cast<float>(_DataTest[i].mDC_Current) << static_cast<float>(_DataTest[i].mmPotential);
return stream;
}


void MainWindow::sendTestData()
{

QByteArray myTestSendData;
QDataStream stream(&myTestSendData, QIODevice::WriteOnly);
stream.setVersion(QDataStream::Qt_5_9);
stream << QDateTime::currentDateTime();
for(int i = 0; i < 40; i++)
stream << _DataTest[i].mmyChannel_Nr << _DataTest[i].mAC_Volt
<< _DataTest[i].mDC_Volt << _DataTest[i].mAC_Current
<< _DataTest[i].mDC_Current << _DataTest[i].mmPotential;
testUdpSocket->writeDatagram(myTestSendData, QHostAddress::LocalHost, 50885);
}


receiveObjects.h



#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QUdpSocket>
#include <QTimer>
#include <QDebug>
#include <QDateTime>

namespace Ui {
class MainWindow;
}

struct DataChannels
{
QString myChannel_Nr;
float AC_Volt;
float DC_Volt;
float AC_Current;
float DC_Current;
float mPotential;

};

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
friend QDataStream& operator >> (QDataStream &stream, QVector <DataChannels> &receivePacket);

private slots:
void readAllValue();

private:
Ui::MainWindow *ui;
QUdpSocket *readSocket;
QVector < DataChannels > receivePacket;
};

#endif // MAINWINDOW_H

,

receiveObjects.cpp



#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);

readSocket = new QUdpSocket(this);
readSocket->bind(QHostAddress::LocalHost, 50885);
receivePacket.resize(40);
connect(readSocket, SIGNAL(readyRead()), this, SLOT(readAllValue()));
}

MainWindow::~MainWindow()
{
delete ui;
}

QDataStream& operator >>(QDataStream &stream, QVector<DataChannels> &receivePacket)
{
QDateTime mDateTime;
quint32 tempInt;
QString tempString;
receivePacket.resize(40);

stream >> mDateTime;
for(int i = 0; i < 40; i++)
{
stream >> tempString; receivePacket[i].myChannel_Nr = tempString;
stream >> tempInt; receivePacket[i].AC_Volt = tempInt;
stream >> tempInt; receivePacket[i].DC_Volt = tempInt;
stream >> tempInt; receivePacket[i].AC_Current = tempInt;
stream >> tempInt; receivePacket[i].DC_Current = tempInt;
stream >> tempInt; receivePacket[i].mPotential = tempInt;
}
return stream;
}

void MainWindow::readAllValue()
{
QByteArray mReceiveDatagram;

do
{
mReceiveDatagram.resize(int(readSocket->pendingDatagramSize()));
readSocket->readDatagram(mReceiveDatagram.data(), mReceiveDatagram.size());
} while(readSocket->hasPendingDatagrams());

QDateTime dateTime;
QDataStream stream(&mReceiveDatagram, QIODevice::ReadOnly);
stream.setVersion(QDataStream::Qt_5_9);
stream >> dateTime;
for(int i = 0; i< 40; i++)
{
stream >> receivePacket[i].myChannel_Nr >> receivePacket[i].AC_Volt >> receivePacket[i].DC_Volt
>> receivePacket[i].AC_Current >> receivePacket[i].DC_Current >> receivePacket[i].mPotential;
}
}

malone
17th January 2019, 18:43
nobody helps me

anda_skoa
17th January 2019, 20:25
Do you have a test, e.g. unittest, that checks for serialization and deserialization without any network involvement?

Do you receive datagrams?

Any reason you discard all datagrams but the last?

Your stream operators aren't used so they can't really be the problem.

If your goal is to use them in a later stage of your program, you should probably rethink using a hard coded magic number (40) when looping :-)

Cheers,
_

malone
18th January 2019, 08:12
thank you already for your answer,


Do you have a test, e.g. unittest, that checks for serialization and deserialization without any network involvement?

_
i don't have. i only started both programs(SendObject and ReceiveObject). Normally , the class sendObject is for serialization of my struct Object and the class ReceiveObject is for deserialization, i th thought so. Maybe it's my code that was badly written.


Do you receive datagrams? _
i don't receive anything. i tried to sniff my network with wireshark, something is sent that i cannot read or receive on my Class receiveObject.


Any reason you discard all datagrams but the last?_ i want to send all datagrams, that is the goal of my program. i didn't know that i discard all datagrams except the last


Your stream operators aren't used so they can't really be the problem._ How to use it?


If your goal is to use them in a later stage of your program, you should probably rethink using a hard coded magic number (40) when looping :-)_ i didn't understand what do you mean? normally with my class "sendObject" i want to send 40 object of type struct on the socket. One object of this struct contains 6 elements.

I written a simple program that send only one Object of type struct and receives it. It works fine. i can receive something that i send but i have to send every element of my object of type struct.
So now if i want to send 40 objects of type struct containing each 6 elements, i have to send element by element. That's long. That's why i wanted to integrate a QVector that i cannot send and read.

thank you already for your answer,


Do you have a test, e.g. unittest, that checks for serialization and deserialization without any network involvement?

_
i don't have. i only started both programs(SendObject and ReceiveObject). Normally , the class sendObject is for serialization of my struct Object and the class ReceiveObject is for deserialization, i th thought so. Maybe it's my code that was badly written.


Do you receive datagrams? _
i don't receive anything. i tried to sniff my network with wireshark, something is sent that i cannot read or receive on my Class receiveObject.


Any reason you discard all datagrams but the last?_ i want to send all datagrams, that is the goal of my program. i didn't know that i discard all datagrams except the last


Your stream operators aren't used so they can't really be the problem._ How to use it?


If your goal is to use them in a later stage of your program, you should probably rethink using a hard coded magic number (40) when looping :-)_ i didn't understand what do you mean? normally with my class "sendObject" i want to send 40 object of type struct on the socket. One object of this struct contains 6 elements.

I written a simple program that send only one Object of type struct and receives it. It works fine. i can receive something that i send but i have to send every element of my object of type struct.
So now if i want to send 40 objects of type struct containing each 6 elements, i have to send element by element. That's long. That's why i wanted to integrate a QVector that i cannot send and read.

Added after 6 minutes:

this is my simple code to send and receice element by element of an object of type struct

send.h



namespace Ui {
class MainWindow;
}

struct DataChannels
{
QString myChannel_Nr;
float AC_Volt;
float DC_Volt;
float AC_Current;
float DC_Current;
float Potential;
};


class MainWindow : public QMainWindow
{
Q_OBJECT

public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void sendTestData();

void on_pushButton_clicked();

private:
Ui::MainWindow *ui;
QUdpSocket *testUdpSocket;
QTimer *testTimer;
DataChannels mData, temp;
};

#endif // MAINWINDOW_H


send.cpp



MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
testUdpSocket = new QUdpSocket(this);



mData.myChannel_Nr = tr("Kanal ") +QString::number(1);
mData.AC_Volt = 150.320;
mData.DC_Volt = 80.67;
mData.AC_Current = 5.0;
mData.DC_Current = 3.0;
mData.Potential = 6.0;
temp = mData;


testTimer = new QTimer(this);
connect(testTimer, SIGNAL(timeout()), this, SLOT(sendTestData()));
testTimer->start(200);


}

MainWindow::~MainWindow()
{
delete ui;
}



void MainWindow::sendTestData()
{

QByteArray myTestSendData;
QDataStream stream(&myTestSendData, QIODevice::WriteOnly);
stream.setVersion(QDataStream::Qt_5_9);
stream << QDateTime::currentDateTime() << mData.myChannel_Nr << mData.AC_Volt
<< mData.DC_Volt << mData.AC_Current << mData.DC_Current << mData.Potential;
testUdpSocket->writeDatagram(myTestSendData, QHostAddress::LocalHost, 50885);


}

void MainWindow::on_pushButton_clicked()
{
QMainWindow::close();
}



receive.h



namespace Ui {
class MainWindow;
}

struct DataChannels
{
QString myChannel_Nr;
float AC_Volt;
float DC_Volt;
float AC_Current;
float DC_Current;
float Potential;

};

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();

private slots:
void readAllValue();

private:
Ui::MainWindow *ui;
QUdpSocket *readSocket;
DataChannels readPacket;
};

#endif // MAINWINDOW_H


receive.cpp


MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);

readSocket = new QUdpSocket(this);
readSocket->bind(QHostAddress::LocalHost, 50885);
connect(readSocket, SIGNAL(readyRead()), this, SLOT(readAllValue()));
}

MainWindow::~MainWindow()
{
delete ui;
}

void MainWindow::readAllValue()
{
QByteArray mReceiveDatagram;

do
{
mReceiveDatagram.resize(int(readSocket->pendingDatagramSize()));
readSocket->readDatagram(mReceiveDatagram.data(), mReceiveDatagram.size());
} while(readSocket->hasPendingDatagrams());

QDateTime dateTime;
QDataStream stream(&mReceiveDatagram, QIODevice::ReadOnly);
stream.setVersion(QDataStream::Qt_5_9);
stream >> dateTime >> readPacket.myChannel_Nr >> readPacket.AC_Volt >> readPacket.DC_Volt
>> readPacket.AC_Current >> readPacket.DC_Current >> readPacket.Potential;

}

anda_skoa
18th January 2019, 12:26
i don't have. i only started both programs(SendObject and ReceiveObject). Normally , the class sendObject is for serialization of my struct Object and the class ReceiveObject is for deserialization, i th thought so. Maybe it's my code that was badly written.

It is always a good idea narrow down a problem by testing different steps separately.

Serialization/deserialization, for example, can be easily tested with a QBuffer instead of a socket.



i don't receive anything. i tried to sniff my network with wireshark, something is sent that i cannot read or receive on my Class receiveObject.

Well, then you have to debug why that does not happen before concerning yourself if you possibly also have problems in the deserialization code.

If there is no data to read, there is no data to deserialize.



i want to send all datagrams, that is the goal of my program. i didn't know that i discard all datagrams except the last

You have a loop that reads all available datagrams into a single buffer, each loop iteration overwriting the previously read data.
Thus you end up with only the data of the last datagram.



How to use it?

By streaming the vector into the stream



i didn't understand what do you mean? normally with my class "sendObject" i want to send 40 object of type struct on the socket.

The loops use "40" as hard coded value. If the vector is shorter the loop will crash. If the vector is longer, some values won't be sent.

Iterating over a vector by index usually refers to the vector's size or element count.
Sending a vector would then also first send that number so that the receiving side know how many elements to expect.



I written a simple program that send only one Object of type struct and receives it. It works fine.


Good.
Next step is to see how many bytes get written when you send a full vector of elements and the compare that to the number of bytes received on the other side.

Separately ensure that serialization and deserialization work as a round trip.

Cheers,
_

malone
19th January 2019, 12:23
Next step is to see how many bytes get written when you send a full vector of elements and the compare that to the number of bytes received on the other side.

but the problem is that i don't get sent with QDatagram a full vector of elements. You told me, that when i used a for-loop, i discard all datagrams except the last. Can show me with a simple code example, how i can send a full vector of elements. May be 20 objetc of type struct with 4 elements.
Thank you!

d_stranz
19th January 2019, 19:49
You told me, that when i used a for-loop, i discard all datagrams except the last.

In your first post, in receiveObjects.cpp, the loop starting at line 45 reads one pending datagram each time through the loop, and it stores it into the same datagram instance. This overwrites whatever the previous contents might have been because before reading the datagram, the object gets resized to whatever size is waiting to be read. The result is that the final datagram object only contains the last datagram you read.