I`m writing application, which send voice from one computer to other. I have simple implementation of "sender"
VoiceSender::VoiceSender(QAudioFormat &format, QString ip){
input = new QAudioInput(format);
QUdpSocket* socket = new QUdpSocket();
socket->connectToHost(ip, 14433);
input->start(socket);
}
Just get all data from mic and send it as UDP to specified IP.
In the other side I have program, which get all data received by UDP, and play it by audio system
Interlocutor::Interlocutor(QAudioFormat &format){
socket = new QUdpSocket();
socket->bind(QHostAddress::Any, 14433);
QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
if (!info.isFormatSupported(format))
format = info.nearestFormat(format);
output = new QAudioOutput(format);
device = output->start();
connect(socket, SIGNAL(readyRead()), this, SLOT(playData()));
}
void Interlocutor::playData()
{
qDebug() << QDateTime::currentDateTime();
while (socket->hasPendingDatagrams())
{
QByteArray data;
data.resize(socket->pendingDatagramSize());
socket->readDatagram(data.data(), data.size());
device->write(data.data(), data.size());
}
}
If both computers locating in the local network this works well, i can transfer my voice between computers. I tried to run it in the VPN. For it I run Hamachi in both computers, and got nothing. Slot playData() is never called. I run Wireshark and seen that computer get UDP packages, but Qt doesnt. What should I do to fix it.
Thanks.
You should check the result of the QUdpSocket::bind function.
bool QUdpSocket::bind ( const QHostAddress & address, quint16 port )
On success, the functions returns true and the socket enters
BoundState; otherwise it returns false.
if (!socket->bind(QHostAddress::Any, 14433))
{
QMessageBox::warning(0, "Error", "Binding Failed");
}
If binding is failed check if firewall is not blocking you or this port is not used by another application.
Related
I'm trying to see my outgoing UDP traffic in Wireshark.
I created new socket and bind it to my QHostAddress::LocalHost with no errors. I then sent some data writeDatagram and the return value is correct, but I see no outgoing traffic in Wireshark.
// create a socket called from init()
socket = new QUdpSocket(this);
bool ret = socket->bind(QHostAddress::LocalHost, 47000);
if (ret == false)
{
printf("failed to bind socket\n");
}
// create and sent some data called from send()
QHostAddress addr("192.168.5.12"); // addr of my other computer
qint64 size = socket->writeDatagram(QByteArray("udp data"),addr,47000);
printf("sent %d\n",size); // correct size sent 8
I checked the firewall setting and it's the same result if I turn it off.
SOLVED by changing the QHostAddress from localhost to assigned router address.
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
I have a QTcpSocket and I am reading into a loop. Each time a full packet has been read, or there has been an error, I manually check the status of the socket inside the loop, with:
while(true){
if(socket->state()==QAbstractSocket::ConnectedState){
qDebug()<<"Socket status: connected. Looking for packets...";
if(socket->waitForReadyRead(2000)){
//...
}
When I execute de program, once connected and the loop starts, it always prints qDebug()<<"Socket status: connected. Looking for packets..."; and then stucks at waitForReadyRead until some data is ready to be read.
The problem is that disconnections are not detected. If I disconnect from network from the OS options, or even if I unplug the ethernet wire, it behaves the same: Socket state equals QAbstractSocket::ConnectedState, so it goes on, but without receiving anything of course.
I also tried to detect disconnections connecting disconnected() signal (after fist connection) to a reconnect function:
// Detect disconnection in order to reconnect
connect(socket, SIGNAL(disconnected()), this, SLOT(reconnect()));
void MyClass::reconnect(){
qDebug()<<"Signal DISCONNECTED emitted. Now trying to reconnect";
panelGUI->mostrarValueOffline();
socket->close();
prepareSocket((Global::directionIPSerialServer).toLocal8Bit().data(), 8008, socket);
qDebug()<<"Reconnected? Status: "<<socket->state();
}
But signal is never emited, because this code is never executed. Which is logical, since it looks like socket state is always ConnectedState.
If I plug again, connection is restored and starts to receive data again, but I do want to detect disconnections to show "Disconnected" at the GUI.
Why is QTcpSocket behaving this way, and how can I solve this problem?
EDIT: I'm creating socket at the class constructor, and then initialising calling prepareSocket function:
socket = new QTcpSocket();
socket->moveToThread(this);
bool prepareSocket(QString address, int port, QTcpSocket *socket) {
socket->connectToHost(address, port);
if(!socket->waitForConnected(2000)){
qDebug()<<"Error creating socket: "<<socket->errorString();
sleep(1);
return false;
}
return true;
}
Finally found the solution in this Qt forum:
If no data is exchanged for a certain while, TCP will start sending
keep-alive segments (basically, ACK segments with the acknowledgement
number set to the current sequence number less one). The other peer
then replies with another acknowledgement. If this acknowledgment is
not received within a certain number of probe segments, the connection
is automatically dropped. The little problem is that the kernel starts
sending keep-alive segments after 2 hours since when the connection
becomes idle! Therefore, you need to change this value (if your OS
allows that) or implement your own keep-alive mechanism in your
protocol (like many protocols do, e.g. SSH). Linux allows you to
change it using setsockopt:
int enableKeepAlive = 1;
int fd = socket->socketDescriptor();
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &enableKeepAlive, sizeof(enableKeepAlive));
int maxIdle = 10; /* seconds */
setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &maxIdle, sizeof(maxIdle));
int count = 3; // send up to 3 keepalive packets out, then disconnect if no response
setsockopt(fd, SOL_TCP, TCP_KEEPCNT, &count, sizeof(count));
int interval = 2; // send a keepalive packet out every 2 seconds (after the 5 second idle period)
setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &interval, sizeof(interval));
I've been facing similar problems with a QT client app. Basically I handle it with Timers, signals and slots. When the app starts up, it starts a 4 second checkConnectionTimer. Every 4 seconds the timer expires, if the client socket state != AbstractSocket::Connected or Connecting, it attempt to connect with clientSocket->connectToHost
When the socket signals "connected()", it starts a 5 second server heartbeat timer. The server should send a one byte heartbeat message to its clients every 4 seconds. When I get the heartbeat (or any type of message signaled by readyRead()), I restart the heartbeat timer. So if the heartbeat timer ever has a timeout, I assume the connection to be down and it calls clientSocket->disconnectFromHost ();
This is working very well for all different kinds of disconnects on the server, graceful or otherwise (yanking cable). Yes it requires custom heartbeat type of stuff, but at the end of the day it was the quickest and most portable solution.
I wasn't to keen on setting KEEPALIVE timeouts in the kernel. This way its more portable.
In the constructor:
connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readMessage()));
connect(clientSocket, SIGNAL(connected()), this, SLOT(socketConnected()));
connect(clientSocket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
connect(heartbeatTimer, SIGNAL(timeout()), this, SLOT(serverTimeout()));
...
// Other Methods
void NetworkClient::checkConnection(){
if (clientSocket->state() != QAbstractSocket::ConnectedState &&
clientSocket->state() != QAbstractSocket::ConnectingState){
connectSocketToHost(clientSocket, hostAddress, port);
}
}
void NetworkClient::readMessage()
{
// Restart the timer by calling start.
heartbeatTimer->start(5000);
//Read the data from the socket
...
}
void NetworkClient::socketConnected (){
heartbeatTimer->start(5000);
}
void NetworkClient::socketDisconnected (){
prioResponseTimer->stop();
}
void NetworkClient::serverTimeout () {
clientSocket->disconnectFromHost();
}
try this signal slot connection:
connect(this, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
this, SLOT(onStateChanged(QAbstractSocket::SocketState)));
at slot implementation:
void TCPWorker::onStateChanged(QAbstractSocket::SocketState socketState ){
qDebug()<< "|GSTCPWorkerThread::onStateChanged|"<<socketState;
...}
I have the same problem, but instead your problem ( always connected ), i have delay 4-5 seconds to receive disconnect signals, after unplugget ethernet wire.
Still looking solution, post answer if find.
try my template of client in Qt:
class Client: public QTcpSocket {
Q_OBJECT
public:
Client(const QHostAddress&, int port, QObject* parent= 0);
~Client();
void Client::sendMessage(const QString& );
private slots:
void readyRead();
void connected();
public slots:
void doConnect();
};
on cpp:
void Client::readyRead() {
// if you need to read the answer of server..
while (this->canReadLine()) {
}
}
void Client::doConnect() {
this->connectToHost(ip_, port_);
qDebug() << " INFO : " << QDateTime::currentDateTime()
<< " : CONNESSIONE...";
}
void Client::connected() {
qDebug() << " INFO : " << QDateTime::currentDateTime() << " : CONNESSO a "
<< ip_ << " e PORTA " << port_;
//do stuff if you need
}
void Client::sendMessage(const QString& message) {
this->write(message.toUtf8());
this->write("\n"); //every message ends with a new line
}
i omitted some code as constructor and slots connections..
try with this and if it doesn t work maybe there is something wrong on server side..
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();
}
}