C++ Qt - QTcpSocket emit readyRead() but canReadLine() always false - c++

I am writing a client in C++ and a server in Python.
The server accepts the connection from the client, and sends to the client its player ID number, formated for the regular expression "id\s\d". (e.g. "id 3")
if s is serversocket:
print "Listening..."
if accept_connection or nb_player < 5:
connection, client_address = s.accept();
print 'New connection from ', client_address
connection.setblocking(0)
inputs.append(connection)
# Send player I to new connection
connection.send("id "+str(len(inputs)-1))
The client initializes its socket, and connect. I implemented connected() to display a message on the GUI, if it is emitted. It is emitted without problem. Same thing on the server side, I receive the connection without issues.
Window::Window(QWidget *parent) :
QDialog(parent),
ui(new Ui::Window)
{
ui->setupUi(this);
/* Initialize socket */
socket = new QTcpSocket(this);
socket->connectToHost("localhost", 13456);
connect(socket, SIGNAL(readyRead()), this, SLOT(data_received()));
connect(socket, SIGNAL(connected()), this, SLOT(connected()));
}
The server receives data from the client without problem. It is the client that does not receive the information correctly.
void Window::data_received(){
QRegExp id_re("id\\s(\\d)");
while (socket->canReadLine()){
/* Read line in socket (UTF-8 for accents)*/
ui->log->append("listening...");
QString line = QString::fromUtf8(socket->readLine()).trimmed();
/* Player ID returned by server */
if ( id_re.indexIn(line) != -1){
//Test
ui->log->append("The ID arrived");
//Extract ID
QString id_str = id_re.cap(1);
//Put in data structure of player
player->set_player_id(id_str);
//Display message
ui->log->append(QString("You are Player "+ player->get_player_id()));
}
}
}
get_player_id() returns a QString
I targeted my problem down, and it seems that canReadLine() is never returning true, therefore I can never read it. What could cause that?

It is because canReadLine() looks for "\n". Python does not automatically add it, therefore, there was no end-of-line to my string of character. Simply adding "\n" in the Python code solved my problem.

Related

QUdpSocket - datagram is being received twice, why?

I am receiving a datagram twice on my QUdpSocket even though I am watching on wireshark and it is only received once. I create the socket and listen on port 11112. There is another device that emits data on this port which I am listening for. I consistently get two messages for each actual message sent. Im not sure what is causing this. Any thoughts?
Stripped down code :
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
m_socket = new QUdpSocket(this);
connect (m_socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
m_socket->bind(11112, QUdpSocket::ShareAddress);
}
MainWindow::~MainWindow()
{
delete ui;
delete m_socket;
}
void MainWindow::readPendingDatagrams()
{
QByteArray buffer;
QHostAddress sender;
quint16 port;
while(m_socket->hasPendingDatagrams())
{
int s = m_socket->pendingDatagramSize();
buffer.resize(s);
//for some reason there are two datagrams on the line.
// I have verified with wireshark that there is only one from the
// sender so not sure what is happening under the hood...
m_socket->readDatagram(buffer.data(),buffer.size(),&sender, &port);
QString source = sender.toString().split(":")[3];
if (source == "172.20.23.86")
{
qInfo() << buffer <<endl;
}
}
}
void MainWindow::onSocketStateChange(QAbstractSocket::SocketState state)
{
if ( state == QAbstractSocket::BoundState ) {
connect(m_socket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));
}
}
This may happen if the datagram is sent to a broadcast address, and you’re bound to all interfaces (0.0.0.0), and there are two interfaces the datagram is received on. To exclude this possibility, switch to the receiveDatagram API and dump the full details of the datagram you’ve received. My bet is that the interfaces you receive it on will be different each time.
You're also connecting the readPendingDatagrams slot potentially multiple times, and it may thus be fired multiple times, although hasPendingDatagrams should return false the second time round - so while this may be not be the problem, it is a problem that you must fix. It should only be connected once - when you construct the socket, i.e. in the constructor.
Unslander Monica is correct, it binds to all interfaces default, you can fix it by m_socket->bind(QHostAddress::LocalHost,11112);

Qt, send UDP through VPN(Hamachi)

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.

QT: How to get data from socket tcpserver at port 1000

I listened the 1000 port with hercules terminal then the data came out.
Now I am coding the program in QT as below
void SocketTest::Test()
{
socket = new QTcpSocket(this);
connect(socket, SIGNAL(connected()), this, SLOT(connected()));
connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
connect(socket, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWritten(qint64)));
qDebug()<<"Connect!";
socket->connectToHost("192.168.0.44",1000);
if (!socket->waitForConnected(3000))
{
qDebug()<<"error"<<socket->errorString();
}
}
and it shows- "socket operation timeout"
My host ip is 192.168.0.44 port 1000 and My computer ip is 192.168.0.5.
How can I get data as in figure 1 with QT? and please show me some examples because I am a noobie in this field.
According to the screenshot, 192.168.0.44 is the IP of the client, not the server. Try connecting to 192.168.0.5:1000 instead.
After connecting to the sever,the best approach is to receive data in an asynchronous mode by connecting the readyRead() signal of the socket to a slot :
connect( socket , SIGNAL(readyRead()),
this, SLOT(tcpReady()) );
From the Qt documentation :
This signal is emitted once every time new data is available for
reading from the device. It will only be emitted again once new data
is available, such as when a new payload of network data has arrived
on your network socket, or when a new block of data has been appended
to your device.
You can read data in the slot which is connected to readyRead signal :
void SocketTest::tcpReady()
{
unsigned long long bytesAvailable = socket->bytesAvailable();
char buf[bytesAvailable];
socket.read(buf, bytesAvailable);
for(int i=0;i<bytesAvailable;i++)
qDebug() << buf[i];
}
On your readyRead slot you can use the readAll() function to retrieve all data available on that socket.
If you need its as a char array, just use QByteArray::data();
Example connecting to Google:
Client::Client(QObject *parent) : QObject(parent)
{
socket = new QTcpSocket(this);
connect(socket, SIGNAL(readyRead()), SLOT(readyRead()));
socket->connectToHost("google.com", 80);
if (socket->waitForConnected())
socket->write("HEAD / HTTP/1.0\r\n\r\n\r\n");
}
void Client::readyRead()
{
QByteArray data = socket->readAll();
qDebug() << data.data(); //Gives a copy of the QByteArray as char array
}
And here you can see the result:

QTcpSocket / QTcpServer memory management / server crash

I am designing and making a server that should be able to handle about 100+ hits per second. The information I am getting from the server is just the HTTP header. Based on the information from the header, it will query a database(different thread) for some information and send the final information back to the QTcpServer which create an output string, and send back a HTTP Response. I am having a big problem with this that I cannot debug. My code look similar to this:
TCPInterface::TCPInterface(QObject *parent): QTcpServer(parent)
{
//start listening for tcp traffic on port 80
listen(QHostAddress::Any, 80);
connect(this,SIGNAL(sendInfo(QTcpSocket*, QString *)), databaseThread, SLOT(recieveInfo(QTcpSocket*, QString*)));
connect(databaseThread, SIGNAL(sendToTCPSend(QTcpSocket *, QString *)), this, SLOT(TCPSend(QTcpSocket*, QString*)));
}
`
void TCPInterface::incomingConnection(int socket)
{
QTcpSocket *s = new QTcpSocket(this);
connect(s, SIGNAL(readyRead()), this, SLOT(readClient()));
//connect(s, SIGNAL(disconnected()), this, SLOT(discardClient()));
s->setSocketDescriptor(socket);
}
`
//void TCPInterface::discardClient()
//{
//QTcpSocket* socket = (QTcpSocket*)sender();
//socket->deleteLater();
//}
`
void TCPInterface::readClient()
{
QTcpSocket* socket = (QTcpSocket*)sender();
QString header;
while(socket->canReadLine())
{
header += socket->readLine();
}
emit sendInfo(socket, headerInfo);
}
`
void databaseThread::recieveInfo(QTcpSocket* socket, QString* headerInfo)
{
QString*outputInfo = getDatabaseInfo(headerInfo);
emit sendToTCPSend(socket, outputInfo);
}
`
void TCPInterface::TCPSend(QTcpSocket* socket, QString* outputInfo);
{
QString response = "HTTP/1.0 200 Ok\r\n";
response += "Content-Type: text/html; charset=\"utf-8\"\r\n";
response += "\r\n" + *outputInfo + "\n";
if(socket->isWritable() && socket->isOpen())
{
socket->write(response.toAscii());
}
//socket->disconnectFromHost();
socket->close();
delete headerInfo;
}
I having one main problem which I have an idea what it is, but cannot find a solution to fix it.
My problem is my memory is constantly increasing as I get more hits. I am sure the cause of this is my QTcpSockets are never being deleted, since I am just closing them. However when I don't use close, and use disconnectFromHost and disconnected/discardClient slot/signal my server will crash with heavy traffic(no message or anything so I am not sure of the exact reason of the crash). Has anyone run into this problem before? Any ideas at all.
I have the same problem!
close() suppose to be as de-constructor of the object. (QT manual QTcpSocket::~QTcpSocket())
There for I suggest to do an experiment: close a socket, and try to re open it. If it fails, it means the socket Object was destroyed, if not means the object should be deletelater()..
In my case the connection is closed by the client, and there for disconnect() SIGNAL is invoked and it trigger the correspond method to your discardClient() SLOT, where I deletelater() the socket.
When I stress test it, it usually crash when I bombard it with 600-800 connection simultaneously on an I5 laptop dual core. it crash every 5 times on average.
Other wise it doesn't.
Happy to discuss it further.
Gil
You should call deleteLater() on your client socket:
connect(socket, SIGNAL(disconnected()),
socket, SLOT(deleteLater()));

Qt bidirectional client server using QTcpSocket and QTcpServer

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();
}
}