Platform independent Qt5 way to get open TCP port - qt

Is there a platform independent way in Qt to get an unused TCP port? I have a need to launch an existing application which must be given an open TCP port in order for it to work.

use QTcpServer is easier way.
bool QTcpServer::listen(const QHostAddress & address = QHostAddress::Any, quint16 port = 0)
If port is 0, a port is chosen automatically, then you use quint16 QTcpServer::serverPort() const to get the "idle" port
then close your Tcp Server
OR
generate a ramdom port, use QTcpSocket to connect it(local connection)
if connected, your port is QTcpSocket::localPort() and close this tcp socket
if not connected, your port is random port;

Do you mean some kind of tcp server? Then there is QTcpServer class.
If you want to start an existiong server, then you need QProcess class. Example:
QString program = "path/to/server";
QStringList arguments;
arguments << "-p" << "1234"; //or what ever you want
QProcess *myProcess = new QProcess(parent);
myProcess->start(program, arguments);

Related

Qt QUdpSocket readDatagram cannot get sender IP address

Qt Version 5.10.0 (MSVC 2015, 32bit)
I have a PC which has a static host address("192.168.0.106"), and a device with an arbitrary IP address assigned by a router. I want to establish a UDP connection between them.
Qt has a udp demo called multicastreceiver, I modified the Receiver::processPendingDatagrams() function as followed:
QByteArray datagram;
QHostAddress senderIP = QHostAddress();
quint16 portx = 0;
while (udpSocket.hasPendingDatagrams()) {
datagram.resize(int(udpSocket.pendingDatagramSize()));
udpSocket.readDatagram(datagram.data(), datagram.size(), &senderIP, &portx);
statusLabel->setText(tr("Received datagram: \"%1\" # %2:%3")
.arg(datagram.constData())
.arg(senderIP.toIPv4Address())
.arg(portx));
}
and in the construction function:
udpSocket.bind(QHostAddress::AnyIPv4, 18427, QUdpSocket::ShareAddress);
connect(&udpSocket, SIGNAL(readyRead()),
this, SLOT(processPendingDatagrams()));
I successfully received the udp message, but
senderIP.toIPv4Address() is 0, and senderIP.toString is NULL
portx is 64800 but it is wrong
Could anyone please tell me what is wrong with these codes?
PS: I can get udp message and sender IP address and the right port number via a UDP debug tool(a PC program).
I think you've found a known bug in Qt:
https://bugreports.qt.io/browse/QTBUG-64784
This is fixed in Qt 5.9.4 - and I believe in 5.10.1 also.
See also the commit.

TCP server created in C language not working on internet

I have created a very simple server program to accept a connection send "Hello World" back to client.I connected to server (localhost) using telnet and it works fine.Now I want to run it over internet and its not working. I tried binding it to my public IP address(search it on google) and it doesn't work.`server_socket=socket(AF_INET,SOCK_STREAM ,0);
serverAddr.sin_family = AF_INET;
serverAddr.sin_port= htons(7892);
serverAddr.sin_addr.s_addr = inet_addr("192.168.43.241");//htonl(INADDR_ANY);//INADDR_ANY;//inet_addr("157.48.97.106");
memset(serverAddr.sin_zero,'\0',sizeof serverAddr.sin_zero);
bind(server_socket, (struct sockaddr *)&serverAddr,sizeof(serverAddr) );
if(listen(server_socket,5)==0)
printf("listening\n");
addr_size=sizeof client_addr;
printf("IP address is: %s\n", inet_ntoa(serverAddr.sin_addr));
while(1)
{
client_socket= accept( server_socket,(struct sockaddr *)&client_addr,&addr_size);
printf("Waiting\n");
printf("client_socket %d\n",client_socket);
int pid=fork();
if(pid>0)
{
printf("PID:%d\n",pid);
dup2(0,client_socket);
}
else
{
dup2(client_socket,0);
printf("%d %d\n",pid,client_socket);
send(client_socket,buffer,strlen(buffer),0);
printf("Message Sent\n");
shutdown(client_socket,0);
close(client_socket);
perror("CLOSE");
printf("Connection Closed\n");
exit(0);
}
}`
In principal you can bind to 0.0.0.0 (which should be the same as the INADDR_ANY that you have in the comment) to listen on all IPv4 addresses. This means you will be able to accept loopback connections as well as connections on all network cards (and thereby from the outside). This should work for you (assuming the remaining program works reliably on loopback).
If you can't connect from outside of the PC on the same network you most likely have a firewall configuration issue. Some OSes by default block incoming connections from the outside if there's no explicit firewall rule that allows it.
If you want to connect from the internet to the PC and you are connected through a router with NAT you also have to configure the router to forward the connection correctly.

Simple Qt code for network simplistic network connection

I'm completely new at using the QtNetwork for connecting computers.
Right now all I want is to see an attempt at a connection. So I create a GUI application and on the mainwindow.cpp I write these two functions as slots for two buttons:
void MainWindow::on_pbTalk_clicked(){
QString IP = ui->leIP->text();
ui->pteLog->appendPlainText("Now Talking to IP: " + IP);
talker = new Talker();
talker->connectToHost(IP,25000);
}
void MainWindow::on_pbListen_clicked(){
ui->pteLog->appendPlainText("Now listening on any port, I think");
listener = new Listener(this);
if (!connect(listener, SIGNAL(newConnection()), this, SLOT(on_newConnections()))){
ui->pteLog->appendPlainText("The connection of slot and signal failed!");
}
}
Now Talker is essentially a QTcpSocket there is nothing reimplemented just yet.
Listener is a QTcpServer with the following code con Listener.cpp:
Listener::Listener(QObject *parent) :
QTcpServer(parent)
{
qDebug() << "Listening on any port";
listen(QHostAddress::Any);
}
void Listener::incomingConnection(int socketDescriptor){
qDebug() << "New connection: " << socketDescriptor;
}
So I run two instances of the same program. One is in my machine. I run the program and push the Listen button (IP 10.255.255.101).
The second instance is run in a virtual machine (IP 10.255.255.215) where I run the program and push the Talk button. This, as I understand should attempt to open a connection to IP (which is 10.255.255.101) at port 25000 and I should get a "New connection" message in the console. However no such message appears. And since this is not working, I'm not moving on.
Can any one tell me what I might be doing wrong?
Check the documenation of QTcpServer::listen - it says:
Tells the server to listen for incoming connections on address address
and port port. If port is 0, a port is chosen automatically. If
address is QHostAddress::Any, the server will listen on all network
interfaces.
QHostAddress::Any means that you are listening on all network interfaces, not ports. (For example, if you want to have a local server only, you could use QHostAddress::LocalHost - check QHostAddress::SpecialAddress for more like that.
If you want to set the port manually, you have to call:
listen(QHostAddress::Any, 25000);
If not, you can get the automatically chosen port by calling
quint16 port = serverPort();
The "listening on any port" idiom isn't available for your use; it's not how UDP and TCP were meant to be used. Most likely you shouldn't be designing your communications that way. Use a dedicated port.
If you want to build a packet sniffer, you'll have to use the platform-specific mechanisms designed for that. There are libraries that help you with that task, the most notable would be WinPcap on Windows and cross-platform libpcap from the TcpDump project.

Opening a virtual serial port created by SOCAT with Qt

I'm developping a Qt5 application on MacOS.
I would like to test my application serial port communication.
I'd like to use socat but I'm unable to open the port created with socat: QSerialPortInfo::availablePorts() lists only the /dev/cu-XXXXXX ports...
Socat port creation example:
socat pty,link=/dev/mytty,raw tcp:192.168.254.254:2001&
After this you get your pseudo port /dev/mytty
Now you can reference this port via QSerialPort
serial = new QSerialPort("/dev/mytty");
You might be having troubles because of the symlink.
You could try something like this:
QFileInfo file_info("/dev/mytty");
QSerialPort* serial = nullptr;
if (file_info.isSymLink()) {
serial = new QSerialPort(file_info.symLinkTarget());
} else {
serial = new QSerialPort(file_info.path());
}
serial->open(QIODevice::ReadWrite);
You could also construct a QSerialPortInfo class with those paths instead of creating a port directly.
Maybe it's just a permission issue.
Make sure the user running your application has permition to access the virtual port.

Rebind using new QUdpSocket

I have a network application which uses UDP broadcasts for device discovery, but only accepts one connection at a time. So, when a new TCP connection is made, I delete the QUdpSocket that was used for discovery.
However, when the remote device is disconnected, I want to create a new QUdpSocket and start listening again:
// Set up a UDP server to respond to any "discovery" messages:
udpServer = new QUdpSocket(this);
if (udpServer -> bind(QHostAddress::Any, DISCOVERY_PORT))
connect(udpServer, SIGNAL(readyRead()),
this, SLOT(beDiscovered()));
else
{
fprintf(stderr, "UDP port not bound successfully: %d, ", udpServer ->error());
fprintf(stderr, udpServer ->errorString().toLocal8Bit());
fprintf(stderr, "\r\n");
fflush(stderr);
#ifdef WIN32
_commit(_fileno(stderr));
#else
fsync(_fileno(stderr));
#endif
}
The re-bind fails, however, with code 8, "The bound address is already in use".
So, how can I make sure that when the 'old' QUdpSocket was deleted, it fully releases the address(es) it was bound to?
Alternatievly, should I be binding with QUdpSocket::ShareAddress or QUdpSocket::ReuseAddressHint? This doesn't seem right, as neither really describe the behaviour I want, namely an exclusive binding for my QUdpSocket during its lifetime, and in any case QUdpSocket::ShareAddress is supposed to be the default on Windows.
Thanks,
Stephen.
...so in other words the question has answered itself!

Resources