all
I want to use QUdpSocket to send udp packet to get config parameter from specific server,but It failed and I can not capture the sending packet using wireshark.here is my code:
CGetConfig.cpp:
CGetConfig::CGetConfig(const QString &conf_server,const uint16_t port)
:m_conf_server(conf_server)
,m_port(port)
{
m_socket = NULL;
}
CGetConfig::~CGetConfig()
{}
void CGetConfig::init()
{
// create a QUDP socket
m_socket = new QUdpSocket(this);
m_socket->bind(QHostAddress::LocalHost, 12345);
connect(m_socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
m_ip_addr = get_ip_address(m_conf_server);
}
bool CGetConfig::get_reflector(const QString &mac)
{
qDebug() << "CGetConfig::get_reflector():Entry\n";
if(m_ip_addr.isEmpty())
{
qDebug() << "CGetConfig::get_reflector():ip address of cofnig server could not be resolved\n";
return 0;
}
QString msg("id=1&mac=");
msg+= mac;
msg+= "&get_config=fw_type=v.1,cfg_ver=4,set_ver=0,ip=192.168.1.101";
qDebug() << m_ip_addr;
qDebug() << m_port;
qDebug() << msg.toLatin1();
int count = 0;
while(count < 3)
{
int t = m_socket->writeDatagram(msg.toLatin1(), QHostAddress(m_ip_addr), m_port);
count++;
}
}
Main.cpp
CGetConfig cfg(cfg_server,cfg_port);
cfg.init();
local_mac = "00d033120001";
cfg.get_reflector(local_mac);
Can anyone help me figure out the problem?
Related
I have QTcpServer. I want to send large data from client side and how to catch signal, when all data is received on server?
"while (socket->bytesavailable)" doesn't work.
For example:
when qbytearray size is 9000, which is send from client, on the server it's 4000 or 5000...
Example Two:
In this Case readyRead() SIGNAL Is Emited 8 times.
void Client::SendMessage(std::vector<QString>)
{
MyClass _Send;
_Send.Age = 22;
_Send.School = 14;
_Send.Name = "Taz";
QVector<MyClass2> vv;
for (int i = 0; i < 15000; i++) {
vv.push_back(MyClass2(24, "leri"));
vv.push_back(MyClass2(22, "tazo"));
}
_Send.vctr = vv;
QByteArray bytes;
QDataStream stream(&bytes, QIODevice::WriteOnly);
int FunctionUID = 331;
int ij, ik = ij = 169;
MyClass2 faf(-31, "15");
stream << FunctionUID << _Send << faf << ij << ik;
socket->write(bytes);
}
void Server::ImReady()
{
QByteArray buf;
buf = socket->readAll();
QDataStream stream(&buf, QIODevice::ReadOnly);
int FunctionUID, ij, ik;
MyClass vv;
MyClass2 vv1;
stream >> FunctionUID >> vv >> vv1 >> ij >> ik;
qDebug() << vv.vctr.size() << "faf";
}
void Server::incomingConnection(qintptr val)
{
qDebug() << "Client Connected" << val;
socket = new QTcpSocket;
socket->setSocketDescriptor(val);
if (!socket) {
return;
}
connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater()));
connect(socket, SIGNAL(readyRead()), this, SLOT(ImReady()));
}
TCP does not send messages, it is a stream of data. This means you can't just read all data that's there, and consider this one message. Instead one usually sends a header, containing the message size, and then the receiver knows how much to read to get the whole message (and just this one, not read into the next).
This means your slot would do something like this
void Server::ImReady()
{
uint32 size;
socket->read(&size, 4);
uint32 readTotal = 0;
do {
readTotal += socket->read(buffer, size-readTotal);
} while (readTotal < size);
}
You could put a line like
if (socket->bytesAvailable() == 0)
return;
at the beginning of the slot, and then you would not care at all if the signal is emitted more than once per message.
Note that the code above needs additional error handling, e.g. you must make sure the first read reads all 4 bytes, and always handle a return value of -1.
I'm working with Qt 5.9 and I'm using a bidirectional (send and receive) QUdpSocket.
How can I avoid receiving same message has just sent on the same socket?
Here a snippet of the code
// Socket init
this->UdpSocket->bind( QHostAddress::Any, ARTNET_PROTOCOL_PORT );
connect( this->UdpSocket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()), Qt::UniqueConnection );
[...]
void ArtNetManager::readPendingDatagrams()
{
QNetworkDatagram networkDatagram;
qDebug("Udp datagram received");
while( this->UdpSocket->hasPendingDatagrams() )
{
networkDatagram = this->UdpSocket->receiveDatagram();
qDebug("Received datagram from IP address: %s", networkDatagram.senderAddress().toString().toLatin1().data() );
this->receiveDatagram( networkDatagram.data() );
}
}
void ArtNetManager::sendDatagram()
{
QByteArray ArtNet_RawMsg;
ArtNet_RawMsg.append( "Test program" );
// Writes data on the UDP socket
qint64 sentBytes = this->UdpSocket->writeDatagram( ArtNet_RawMsg, QHostAddress::Broadcast, ARTNET_PROTOCOL_PORT );
if( sentBytes == -1 )
{
qDebug("Cannot send data on UPD socket. Error: %d", this->UdpSocket->error() );
}
else if( sentBytes != ArtNet_RawMsg.size() )
{
qDebug("Wrong number of bytes sent. Bytes sent on socket: %d, tx buffer length: %d", sentBytes, ArtNet_RawMsg.size());
}
}
The messages that you receive are due to the ArtNet behavior. UDP protocol normally doesn't reflect the outgoing traffic back. Some other ArtNet device is doing that.
You could ignore these by keeping a list of a few recently sent messages, and looking them up:
class ArtNetManager : public QObject {
Q_OBJECT
int const m_sentFifoLength = 32;
QList<QByteArray> m_sentFifo;
...
}
void ArtNetManager::sendDatagram() {
sendDatagram({"Test program"});
}
void ArtNetManager::sendDatagram(const QByteArray & msg) {
if (m_sent_fifo.size() >= m_sentFifoLength))
fifo.removeLast();
m_sentFifo.prepend(msg);
auto bytes = m_udpSocket->writeDatagram(msg, QHostAddress::Broadcast, ARTNET_PROTOCOL_PORT);
if (bytes != msg.size())
qWarning() << "can't send datagram" << msg.toHex();
}
void ArtNetManager::readPendingDatagrams() {
while (m_udpSocket->hasPendingDatagrams()) {
auto datagram = m_udpSocket->receiveDatagram();
qDebug() << "received datagram from" << datagram.senderAddress().toString();
receiveDatagram(datagram.data());
}
}
void ArtNetManager::receiveDatagram(const QByteArray & msg) {
auto it = std::find(m_sentFifo.begin(), m_sentFifo.end(), msg);
if (it != m_sentFifo.end()) {
m_sentFifo.erase(it);
return;
}
...
}
I have a Client/Server based Qt application, using QTcpServer and QTcpSocket, I managed to do the connection and send some data back and forth between the client and the server.
The client sends many types of data to the server (string, int, files and a real time audio stream) and since my server impliment a single data input SLOT (readyRead()):
connect(socket, SIGNAL(readyRead()),this, SLOT(readyRead()));
I don't know how could I distinguish between all this received data and call respectively the right function in the server.
Example (in the server):
- if I receive string => call function showData(QString data);
- if I receive file => call function saveFile(QFile file);
- if I receive audio stream => play audio stream
- ...
SERVER:
void Server::newClientConnection()
{
QTcpSocket *socket = server->nextPendingConnection();
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
//...
}
void Server::readyRead()
{
QTcpSocket *clientSocket = qobject_cast<QTcpSocket *>(sender());
if (clientSocket == 0) {
return;
}
QDataStream in(clientSocket);
if (sizeMessageClient == 0)
{
if (clientSocket->bytesAvailable() < (int)sizeof(quint16)){
return;
}
in >> sizeMessageClient;
}
if (clientSocket->bytesAvailable() < sizeMessageClient) {
return;
}
sizeMessageClient = 0;
in >> data;
/*
I don't know the type of the received data !!
- if I receive string => call function showData(QString data);
- if I receive file => call function saveFile(QFile file);
- if I receive audio stream => play audio stream
- ...
*/
}
CLIENT:
Client::Client()
{
socket = new QTcpSocket(this);
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
sizeMessageServer = 0;
}
void Client::readyRead()
{
QDataStream in(socket);
if (sizeMessageServer == 0)
{
if (socket->bytesAvailable() < (int)sizeof(quint16)) {
return;
}
in >> sizeMessageServer;
}
if (socket->bytesAvailable() < sizeMessageServer) {
return;
}
int messageReceived;
in >> messageReceived;
messageReceived = static_cast<int>(messageReceived);
sizeMessageServer = 0;
switch(messageReceived)
{
case 1:
qDebug() << "send a File";
sendFile();
break;
case 2:
qDebug() << "send a string data";
sendStringData();
break;
case 3:
qDebug() << "stream audio to the server";
streamAudioToServer();
break;
case n:
// ...
}
}
I am not looking for a complete solution, all I am looking for is some guidance in the right direction.
The implementation of your protocol doesn't fully leverage QDataStream in Qt 5.7. Here's how it might look now - it can be quite simple.
First, let's define the requests we know of:
enum class Req : quint32 {
Unknown, String, File
};
Q_DECLARE_METATYPE(Req)
QDataStream & operator<<(QDataStream & ds, Req req) {
return ds << (quint32)req;
}
QDataStream & operator>>(QDataStream & ds, Req & req) {
quint32 val;
ds >> val;
if (ds.status() == QDataStream::Ok)
req = Req(val);
return ds;
}
It'd also be handy to have a transaction RAII helper.
struct Transaction {
QDataStream & stream;
Transaction(QDataStream & stream) : stream{stream} {
stream.startTransaction();
}
~Transaction() {
stream.commitTransaction();
}
bool ok() {
return stream.status() == QDataStream::Ok;
}
};
The client receives requests from the server and signals the need to reply with data. The code that uses the client would react to these signals and reply back by invoking a matching slot. E.g.
void clientUser(Client & client) {
QObject::connect(&client, &Client::needString, &client, [&]{
client.sendString(QStringLiteral{"You got string!"});
});
And:
class Client : public QObject {
Q_OBJECT
QIODevice & m_dev;
QDataStream m_str{&m_dev};
void onReadyRead() {
Transaction tr{m_str};
Req req;
m_str >> req;
if (!tr.ok()) return;
if (req == Req::String)
emit needString();
else if (req == Req::File) {
QString fileName;
m_str >> fileName;
if (!tr.ok()) return;
emit needFile(fileName);
}
else emit unknownRequest(req);
}
public:
Client(QIODevice & dev) : m_dev{dev} {
connect(&m_dev, &QIODevice::readyRead, this, &Client::onReadyRead);
}
Q_SIGNAL void unknownRequest(Req);
Q_SIGNAL void needString();
Q_SIGNAL void needFile(const QString & fileName);
Q_SLOT void sendString(const QString & str) {
m_str << Req::String << str;
}
Q_SLOT void sendFile(const QString & fileName, const QByteArray & data) {
m_str << Req::File << fileName << data;
}
};
The server is very similar. Its user sends the request to a client via request slots. Once the server hears back from the client, it indicates it through the has signals:
class Server : public QObject {
Q_OBJECT
QIODevice & m_dev;
QDataStream m_str{&m_dev};
void onReadyRead() {
Transaction tr{m_str};
Req req;
m_str >> req;
if (!tr.ok()) return;
if (req == Req::String) {
QString str;
m_str >> str;
if (!tr.ok()) return;
emit hasString(str);
}
else if (req == Req::File) {
QString fileName;
QByteArray data;
m_str >> fileName >> data;
if (!tr.ok()) return;
emit hasFile(fileName, data);
}
else emit hasUnknownRequest(req);
}
public:
Server(QIODevice & dev) : m_dev{dev} {
connect(&m_dev, &QIODevice::readyRead, this, &Server::onReadyRead);
}
Q_SIGNAL void hasUnknownRequest(Req);
Q_SIGNAL void hasString(const QString &);
Q_SIGNAL void hasFile(const QString & name, const QByteArray &);
Q_SLOT void requestString() {
m_str << Req::String;
}
Q_SLOT void requestFile(const QString & name) {
m_str << Req::File << name;
}
};
I would like to use ZeroMQ(4.1.2) with Qt (5.2.1).
Idea is to have zmq pub/sub (where server is outside) and sub is qt app.
Currently receive in Qt app runs once, could someone drop hint?
Should ZeroMQ receiver be implemented in some other way?
Currently my code looks like:
mainwindow.h
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_pushButton_clicked();
void readZMQData();
private:
Ui::MainWindow *ui;
QSocketNotifier *qsn;
void *context;
void *subscriber;
};
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
/***** ZMQ *****/
context = zmq_ctx_new ();
subscriber = zmq_socket (context, ZMQ_SUB);
int rc = zmq_connect (subscriber, "tcp://localhost:5556");
char *filter = "";
rc = zmq_setsockopt (subscriber, ZMQ_SUBSCRIBE,filter, strlen (filter));
unsigned int fd=0;
size_t fd_size = sizeof(fd);
rc = zmq_getsockopt(subscriber,ZMQ_FD,&fd,&fd_size);
qsn = new QSocketNotifier(fd, QSocketNotifier::Read, this);
connect(qsn, SIGNAL(activated(int)), this, SLOT(readZMQData()), Qt::DirectConnection);
}
MainWindow::~MainWindow()
{
zmq_close (this->subscriber);
zmq_ctx_destroy (this->context);
delete ui;
}
void MainWindow::readZMQData()
{
qsn->setEnabled(false);
qDebug() << "Got data!";
int events = 0;
std::size_t eventsSize = sizeof(events);
zmq_getsockopt(subscriber,ZMQ_EVENTS, &events, &eventsSize);
if(events & ZMQ_POLLIN){
qDebug() << " ====== Data to read ======";
char *string = s_recv(subscriber);
qDebug() << "DATA: " << string;
free(string);
}
qsn->setEnabled(true);
}
And server app is (from ZeroMQ examples):
#include "zhelpers.h"
int main (void)
{
// Prepare our context and publisher
void *context = zmq_ctx_new ();
void *publisher = zmq_socket (context, ZMQ_PUB);
int rc = zmq_bind (publisher, "tcp://*:5556");
assert (rc == 0);
// Initialize random number generator
srandom ((unsigned) time (NULL));
while (1) {
// Get values that will fool the boss
int zipcode, temperature, relhumidity;
zipcode = randof (100000);
temperature = randof (215) - 80;
relhumidity = randof (50) + 10;
// Send message to all subscribers
char update [20];
sprintf (update, "%05d %d %d", zipcode, temperature, relhumidity);
s_send (publisher, update);
}
zmq_close (publisher);
zmq_ctx_destroy (context);
return 0;
}
First tnx for helping out,
I've found the issue, when ZeroMQ notifies that there is message to read you need to read them all, not just first one.
void MainWindow::readZMQData(int fd)
{
qsn->setEnabled(false);
int events = 0;
std::size_t eventsSize = sizeof(events);
zmq_getsockopt(subscriber,ZMQ_EVENTS, &events, &eventsSize);
if(events & ZMQ_POLLIN){
qDebug() << " ====== Data to read ======";
char *string;
// THIS IS THE TRICK! READ UNTIL THERE IS MSG
while((string = s_recv_nb(subscriber)) != NULL){
qDebug() << "DATA: " << string;
free(string);
}
}
qsn->setEnabled(true);
}
The socket notifier looks like it should work. Have you read the docs on handling it properly? Especially if you are on Windows, it looks like there are special ways to handle it when doing the read... disabling, reading, etc.
http://doc.qt.io/qt-5/qsocketnotifier.html#details
Hope that helps.
As it is not clear what s_recv_nb(zmq::socket_t & socket) is, I'll provide my - slightly more detailed - implemetation of:
void MainWindow::readZMQData()
{
qsn->setEnabled(false);
int events = 0;
std::size_t eventsSize = sizeof(events);
zmq_getsockopt(subscriber,ZMQ_EVENTS, &events, &eventsSize);
if(events & ZMQ_POLLIN){
qDebug() << " ====== Data to read ======";
char *string;
int64_t more;
size_t more_size = sizeof (more);
do {
/* Create an empty ØMQ message to hold the message part */
zmq_msg_t part;
int rc = zmq_msg_init (&part);
assert (rc == 0);
rc = zmq_msg_recv (&part, subscriber, 0);
assert (rc != -1);
/* Determine if more message parts are to follow */
rc = zmq_getsockopt (subscriber, ZMQ_RCVMORE, &more, &more_size);
assert (rc == 0);
string = (char*) zmq_msg_data(&part);
qDebug() << QString(string) ; // << "more" << more;
zmq_msg_close (&part);
} while (more);
}
qsn->setEnabled(true);
}
And one more remark: in case of Windows 64 the filedescriptor fdshould be uint64_t as in zmq_getsockopt returns EINVAL on windows x64 when local address of ZMQ_FD option_val passed
I'm starting to create my first multithread application, using the QT libraries.
Following the qt guide about QTcpServer and QTcpSocket, i wrote a server application that create the connection with this constructor:
Connection::Connection(QObject *parent) : QTcpServer(parent)
{
server = new QTcpServer();
QString ipAddress;
if (ipAddress.isEmpty())
ipAddress = QHostAddress(QHostAddress::LocalHost).toString();
if (!server->listen(QHostAddress(ipAddress),41500))
{
qDebug() << "Enable to start server";
server->close();
return;
}
connect(server,SIGNAL(newConnection()),this,SLOT(incomingConnection()));
}
This is the incomingConnection() function which create a new thread everytime a new client try to connect:
void Connection::incomingConnection()
{
QTcpSocket *socket = new QTcpSocket();
socket = this->nextPendingConnection();
MyThreadClass *thread = new MyThreadClass(socket, server);
qDebug() << "connection required by client";
if (thread != 0)
{
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
else
qDebug() << "Error: Could not create server thread.";
}
Now, this is MyThreadClass:
MyThreadClass::MyThreadClass(QTcpSocket *socket, QTcpServer *parent) : QThread(parent)
{
tcpSocket = new QTcpSocket();
database = new Db();
blockSize = 0;
tcpSocket = socket;
qDebug() << "creating new thread";
}
MyThreadClass::~MyThreadClass()
{
database->~Db();
}
void MyThreadClass::run()
{
qDebug() << "Thread created";
connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(dataAvailable()));
exec();
}
void MyThreadClass::dataAvailable()
{
qDebug() << "data available";
QDataStream in(tcpSocket);
in.setVersion(QDataStream::Qt_4_0);
if (blockSize == 0) {
if (tcpSocket->bytesAvailable() < (int)sizeof(qint16))
return;
in >> blockSize;
}
if (tcpSocket->bytesAvailable() < blockSize)
return;
QString string;
in >> string;
//[...]
}
The code compiles fine but when i start a client (after starting the server), i receive the following error by server:
QObject::connect: Cannot connect (null)::readyRead() to QThread::dataAvailable()
Then the server cannot receive data by the client.
does anyone have any idea?
thanks in advance
Daniele
socket = this->nextPendingConnection();
should be:
socket = server->nextPendingConnection();
because you are using the server member and not this as the active QTcpServer, the class Connection shouldn't even inherit from QTcpServer, but only from QObject.
Also, you are misusing QThread. You should read Signals and slots across threads, and probably Threads and the SQL Module, if Db is using the QtSql module.