I am trying to get data from a LAN-connected infrared camera.
I don't know how to approach packets from the external network.
Here's my code.
The code below was run on Qt 5.9.7 (msvc2017_64) I've changed codes from Qt UDP example. (https://www.bogotobogo.com/Qt/Qt5_QUdpSocket.php)
#include "myudp.h"
MyUDP::MyUDP(QObject *parent) :
QObject(parent)
{
// create a QUDP socket
socket = new QUdpSocket(this);
socket_cam = new QUdpSocket(this);
// The most common way to use QUdpSocket class is
// to bind to an address and port using bind()
// bool QAbstractSocket::bind(const QHostAddress & address,
// quint16 port = 0, BindMode mode = DefaultForPlatform)
socket->bind(QHostAddress::LocalHost, 1234);
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
}
void MyUDP::HelloUDP()
{
QByteArray Data;
QHostAddress camera_loc = QHostAddress("192.168.10.197");
quint16 cameraPort = 32197;
qint64 deg_num = socket->readDatagram(Data.data() ,964, &camera_loc,
&cameraPort);
qDebug() << "Deg_num: " << deg_num; //this returns -1. Therefore, it
seems it can't read any data from camera_loc.
// Sends the datagram datagram
// to the host address and at port.
// qint64 QUdpSocket::writeDatagram(const QByteArray & datagram,
// const QHostAddress & host, quint16 port)
socket->writeDatagram(Data, QHostAddress::LocalHost, 1234);
}
void MyUDP::readyRead()
{
// when data comes in
QByteArray buffer;
buffer.resize(socket->pendingDatagramSize());
QHostAddress sender = QHostAddress("192.168.10.197");
quint16 senderPort = 32197;
// qint64 QUdpSocket::readDatagram(char * data, qint64 maxSize,
// QHostAddress * address = 0, quint16 * port = 0)
// Receives a datagram no larger than maxSize bytes and stores it
// The sender's host address and port is stored in *address and *port
// (unless the pointers are 0).
socket->readDatagram(buffer.data(), buffer.size(),
&sender, &senderPort);
qDebug() << "Message from: " << sender.toString();
qDebug() << "Message port: " << senderPort;
qDebug() << "Message: " << buffer;
}
As I've seen on Wireshark, packets arrived correctly as I expected.
However, my code doesn't work as I expected. (readDatagram on camera_loc returns (-1))
According to other threads, we don't need to connect them because UDP communication doesn't need to make connections.
What I want to make with this code is as follow.
(0. Save data from the camera (192.168.10.197) on a variable using readDatagram) I am not sure this is a really necessary process...
1. Write data to buffer as written in this code (using writeDatagram function).
I could not find solutions even if I struggled.
I thought it would be easy but it wasn't ...
Any advice will be very grateful because I am a newbie to qt and UDP network.
Thanks in advance.
Related
I am able to send and receive to two different programs running on same computer. But not able to do the same when running them on different computers. Both computers are on same Local area network. I am working on windows 10.
#include "communicationmanager.h"
communicationManager::communicationManager(int portNumber,int socketRole)
{
//socketRole:0=Sender 1=Reciever
//socket = new QUdpSocket(this);
PortNumber = portNumber;
socket = new QUdpSocket(this);
if(socketRole == 1)
{
socket->bind(QHostAddress::LocalHost,PortNumber);
connect(socket, SIGNAL(readyRead()), this, SLOT(recieve()));
}
}
communicationManager::~communicationManager()
{
//delete socket;
}
void communicationManager::prepareMessage(QString command,QString message,int recieverID)
{
Command = command;
Message = message;
recieverID = recieverID;
}
void communicationManager::send()
{
QByteArray datagram;
QDataStream out(&datagram, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_13);
out<<Command<<Message<<recieverID;
socket->writeDatagram(datagram, QHostAddress::LocalHost, PortNumber);
}
void communicationManager::recieve()//For recieving data
{
qDebug()<<"recieve";
QByteArray datagram;
do
{
datagram.resize(socket->pendingDatagramSize());
socket->readDatagram(datagram.data(), datagram.size());
} while (socket->hasPendingDatagrams());
QDataStream in(&datagram, QIODevice::ReadOnly);
QString command;
QString message;
int recieverID;
in >>command>>message>>recieverID;
}
You need to bind to QHostAddress::Any in order to actually receive packets from outside the local machine. QHostAddress::LocalHost will only receive traffic from the same physical machine.
I am trying to receive packet from UDP-connected infrared camera. (FLIR Lepton 2.5) And I'm trying to run my codes on Windows 10, Qt Creator 4.5, Qt 5.9.
As you can see on the capture below, my UDP-connected infrared camera sends UDP packets.
And here's my code:
// myudp.cpp
#include "myudp.h"
#include <QNetworkProxy>
MyUDP::MyUDP(QObject *parent) :
QObject(parent)
{
// create a QUDP socket
socket = new QUdpSocket(this);
socket_cam = new QUdpSocket(this);
cam_address = QHostAddress("192.168.10.197");
cam_port = 32197;
connect(socket, SIGNAL(connected()), this, SLOT(readNwrite()));
socket->connectToHost(cam_address, cam_port, QIODevice::ReadWrite);
if (socket->waitForConnected(2000))
qDebug("Connected!");
else
qDebug("Cannot be connected..");
qDebug() << socket->state();
// seems to be connected...
}
void MyUDP::readNwrite()
{
QByteArray data;
qint64 resize_size = socket->pendingDatagramSize();
//socket have NO size(resize_size == -1, ERROR!)
if(resize_size != -1)
{
qDebug() << "data was resized properly; size: "<<resize_size;
data.resize(socket->pendingDatagramSize());
}
else
qDebug() << "data could not be resized(error)";
qint64 det_num;
det_num = socket->readDatagram(data.data(), 964, &cam_address, &cam_port);
qDebug() << "Can receive data(returns -1 if NO): "<<det_num;
//this returns nothing, too!
qDebug() << "Data is here: " << data.data();
}
Here's my code implementation result:
When signal is connected(), data could not be resized(error)
Can receive data(returns -1 if NO): -1
Data is here:
Connected!
QAbstractSocket::ConnectedState
When signal is readyRead(), Connected!
QAbstractSocket::ConnectedState data was resized properly; size: 0
Can receive data(returns -1 if NO): -1
Data is here:
readyRead signal sometimes seems NOT emitted as expected.
But it is obvious that any data is NOT being sent.
I've tried to find examples which are related to UDP network with a remote network. But there were few of them.
According to some threads, people recommended not to use connectToHost function on UDP network. However, I don't know how to make an approach to remote network without using connectToHost.
I want to know how I should correct my code to get packet from a remote network. Any advice will be very grateful for me because I'm a newbie to UDP network, and Qt.
I'm trying to receive UDP packets from an Arduino Uno. Packets are received by the computer(they're visible in wireshark), but aren't seen in my Qt application. There part of my Udp class:
#include "udp.h"
Udp::Udp(QHostAddress adr, quint16 pr) : QObject()
{
address.setAddress(adr.toString());
port = pr;
socket = new QUdpSocket();
status = socket->bind(address,port);
connect(socket,SIGNAL(readyRead()), this, SLOT(readUdp()));
}
void Udp::sendUdp(QByteArray out)
{
socket->writeDatagram(out,address,port);
}
QByteArray Udp::readUdp()
{
QByteArray input;
input.resize(socket->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
socket->readDatagram(input.data(),input.size(),
&sender,&senderPort);
return input;
}
socket->pendingDatagramSize() returns 0(and -1 sometimes).
I do not know QT, but when using berkely socket API, you need to ensure endian
port = htons(pr);
When your application is running, you can run netstat -l in a terminal. Your application should appear on the list
Background:
I have the below C++ code that listens UDP packets on port26009 then outputs the received packets
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
udpSocket.bind(26009); //the port that GUI listens (26009)
connect(&udpSocket, SIGNAL(readyRead()), this, SLOT(readyRead()));
}
void MainWindow::readyRead(){
QByteArray datagram;
do {
datagram.resize(udpSocket.pendingDatagramSize());
udpSocket.readDatagram(datagram.data(), datagram.size());
} while (udpSocket.hasPendingDatagrams());
qDebug() << "Message: " << datagram;
}
On the client side, here is a C code to unicast 20 udp packets: hi0, hi1, ... hi19:
int main(void){
int i;
char msg[5] = {'\0'};
for(i=0; i<20; i++){
snprintf(msg, 4, "hi%d", i);
send_unicast("192.168.5.1", msg, 26009);
memset(msg, 0, sizeof msg);
}
return 0;
}
void send_unicast(char IPaddr[16], char* message, uint16_t destPort){
struct sockaddr_in si_other;
int s, slen = sizeof(si_other);
if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1){
fprintf(stderr, "socket() failed - line817\n");
exit(1);
}
memset((char *) &si_other, 0, sizeof(si_other));
si_other.sin_family = AF_INET;
si_other.sin_port = htons(destPort);
if (inet_aton(IPaddr, &si_other.sin_addr) == 0) {
fprintf(stderr, "inet_aton() failed - line 825\n");
exit(1);
}
if (sendto(s, message, 512, 0, (struct sockaddr *) &si_other, slen) == -1){
fprintf(stderr, "sendto() failed - line830\n");
exit(1);
}
close(s);
}
I run C++ (Server) and C (client) codes on different Linux devices.
Problem:
C code works fine and generates the packets. I can see on Wireshark that the packets are received on receiving end (C++ ).
However, the above C++ code cannot receive (or process) the packets correctly, it is somehow too fast for the code to handle and I see only couple output, e.g.
hi5
hi14
If the frequency of the transmission is significantly slowed down on the C code (adding sleep(1)) then the C++ code outputs the packets fine.
Question:
I use the received UDP packets to update some information on the GUI (Qt). I guess that the slot causes the slowness, and the code would handle the traffic if I used pthread to listen the packets but then how the thread needs to notify the main class so that the GUI can update accordingly?
All in all, how do you recommend to modify C++ code, so that it can handle the fast data traffic and notify GUI to update?
In your readyRead function of MainWindow, I expect this is going to be a problem: -
QByteArray datagram;
do {
qint64 dSize = udpSocket.pendingDatagramSize();
datagram.resize(dSize);
udpSocket.readDatagram(datagram.data(), dSize);
} while (udpSocket.hasPendingDatagrams());
If the first packet of data is, let's say 8 bytes long, you set the QByteArray to 8 bytes and read the data.
While reading 8 bytes, if 6 bytes are received, the second time around that loop you're going to to call resize on the byte array, but this time it's going to reduce it from 8 bytes to 6 and read 6 bytes, throwing away the data you previously read in.
Rather than resizing the QByteArray, I suggest you append the data to it: -
QByteArray datagram;
do
{ datagram.append(udpSocket.pendingDatagramSize());
udpSocket.readDatagram(datagram.data(), datagram.size());
}while (udpSocket.hasPendingDatagrams());
I am trying to implement a bidirectional client-server program, where clients and servers can pass serialized objects between one another. I am trying to do this using Qt (QTcpSocket and QTcpServer). I have implemented programs like this in java, but I can't figure out how to do it using Qt. I've checked out the fortune client and fortune server examples...but from what I can see, the client is simply signaling the server, and the server sends it some data. I need for the client and server to send objects back and forth. I am not looking for a complete solution, all I am looking for is some guidance in the right direction.
I wrote some code, which accepts a connection, but does not accept the data.
SERVER
this class is the server; it should be accepting a connection and outputting the size of the buffer which is being sent. However it is outputting 0
#include "comms.h"
Comms::Comms(QString hostIP, quint16 hostPort)
{
server = new QTcpServer(this);
hostAddress.setAddress(hostIP);
this->hostPort = hostPort;
}
void Comms::attemptConnection(){
connect(server, SIGNAL(newConnection()), this, SLOT(connectionAccepted()));
//socket = server->nextPendingConnection();
server->listen(hostAddress,hostPort);
//receivedData = socket->readAll();
}
void Comms::connectionAccepted(){
qDebug()<<"Connected";
socket = new QTcpSocket(server->nextPendingConnection());
char* rec = new char[socket->readBufferSize()];
qDebug()<<socket->readBufferSize();
}
CLIENT
This class is the client. It should be sending the string 'hello'. It sends it successfully (to my knowledge)
#include "toplevelcomms.h"
#include "stdio.h"
TopLevelComms::TopLevelComms(QString hostIP, quint16 hostPort)
{
tcpSocket = new QTcpSocket();
hostAddress.setAddress(hostIP);
this->hostPort = hostPort;
}
void TopLevelComms::connect(){
tcpSocket->connectToHost(hostAddress,hostPort,QIODevice::ReadWrite);
//tcpSocket->waitForConnected(1);
QString string = "Hello";
QByteArray array;
array.append(string);
qDebug()<<tcpSocket->write(array);
}
Please tell me what I'm doing wrong, or tell me the general logic of establishing what I want in Qt.
QTcpSocket is asynchronous by default, so when you call connectToHost and write in same context it won't be sent, as socket is not connected. You should change your "client" code:
void TopLevelComms::connect(){
tcpSocket->connectToHost(hostAddress,hostPort,QIODevice::ReadWrite);
if(tcpSocket->waitForConnected()) // putting 1 as parameter isn't reasonable, using default 3000ms value
{
QString string = "Hello";
QByteArray array;
array.append(string);
qDebug()<<tcpSocket->write(array);
}
else
{
qDebug() << "couldn't connect";
}
}
Note: you also didn't check if you're able to listen
void Comms::attemptConnection(){
connect(server, SIGNAL(newConnection()), this, SLOT(connectionAccepted()));
//socket = server->nextPendingConnection();
if(server->listen(hostAddress,hostPort))
{
qDebug() << "Server listening";
}
else
{
qDebug() << "Couldn't listen to port" << server->serverPort() << ":" << server->errorString();
}
//receivedData = socket->readAll();
}
And last thing. Note that QTcpServer::nextPendingConnection() return QTcpSocket, so instead of taking that new connection you create new QTcpSocket with nextPendingConnection as parent
void Comms::connectionAccepted(){
qDebug()<<"Connected";
// WRONG! it will use QTcpSocket::QTcpSocket(QObject * parent)
//socket = new QTcpSocket(server->nextPendingConnection());
// use simple asign
socket = server->nextPendingConnection();
// move reading to slot
connect(socket, SIGNAL(readyRead()), this, SLOT(readSocket()));
}
now we will move reading to separate slot
void Comms::readSocket()
{
// note that dynamic size array is incompatible with some compilers
// we will use Qt data structure for that
//char* rec = new char[socket->readBufferSize()];
qDebug()<<socket->readBufferSize();
// note that QByteArray can be casted to char * and const char *
QByteArray data = socket->readAll();
}
I must admit, that it is a lot of errors as for such small code sample. You need to get some knowledge about TCP/IP connections. Those are streams and there is no warranty that whole data chunk will get to you at once
It looks like you have a timing issue. Since your client and server are different processes, there's no way you can guarantee that the entirety of TopLevelComms::connect() is being executed (along with the network data transfer) before your server's connectionAccepted() function tries to read from the socket.
I suspect that if you take advantage of QTcpSocket's waitForReadyRead() function, you should have better luck:
void Comms::connectionAccepted(){
qDebug()<<"Connected";
socket = new QTcpSocket(server->nextPendingConnection());
if( socket->waitForReadyRead() ) {
char* rec = new char[socket->readBufferSize()];
qDebug()<<socket->readBufferSize();
}
}