PDA

View Full Version : Don't receive data on a TCP-IP server client connection



JorgeQT
19th May 2015, 14:05
Hi,

I am quite new using QT and I am trying to implement a TPC-IP server- client. The server has to read every 0.1sec a line of a file with latitude and longitude and send it to the client. But right now I can connect server and client but the client receive nothing. Could someone help me?? Thanks in advance.

SERVER
main.cpp

#include <iostream>
#include <QCoreApplication>
#include "server.h"

int main(int argc, char *argv[]){
QCoreApplication app(argc, argv);
QString ipaddress = QString(argv[1]);
int port = atoi(argv[2]);
Server* server = new Server("127.0.0.1", 1234);
int retVal = app.exec();
return retVal;
}

server.cpp



include "server.h"
#include <iostream>
#include <QTcpServer>
#include <QTcpSocket>
#include <QTimer>
#include <QDateTime>
#include <QSettings>
#include "readdata.h"

Server::Server(QString ipAddress, int port, QObject *parent) :
QObject(parent), mTcpServer(0), mTcpSocket(0)
{
mTcpServer = new QTcpServer(this);
connect(mTcpServer, SIGNAL(newConnection()), this, SLOT(newConnectionSlot()));
if (!mTcpServer->listen(QHostAddress(ipAddress), port)) {
std::cout << "Unable to start the server: " << mTcpServer->errorString().toStdString() << std::endl;
return;
}

std::cout << "The server is running on\n\nIP: "<< ipAddress.toStdString()
<< "\nport: " << mTcpServer->serverPort() << "\n\nRun the Client now.\n" << std::endl;
}

void Server::newConnectionSlot()
{
mTcpSocket = mTcpServer->nextPendingConnection();
connect(mTcpSocket, SIGNAL(disconnected()),
mTcpSocket, SLOT(deleteLater()));

// setup timer to send data at a given interval
mSendTimer = new QTimer(this);
connect(mSendTimer, SIGNAL(timeout()),
this, SLOT(sendSlot()));
mSendTimer->start(40);
}

void Server::sendSlot()
{
if(!mTcpSocket)
return;

readPathData("/home/jorge/Desktop/INStest.kml", &latitude, &longitude);

QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_0);
out << (quint16)0;

for(int i=0; i < latitude.size(); i++){
positionTest.append(QString::number(latitude[i]) + " " + QString::number(longitude[i]) + /*" " + QString::number(height[i])+*/ "\n");
data << positionTest[i];
out << data.at(qrand() % data.size());
out.device()->seek(0);
out << (quint16)(block.size() - sizeof(quint16));
qint64 written_lat = mTcpSocket->write(block, block.size());
}
}


server.h


#ifndef SERVER_H_
#define SERVER_H_

#include <QObject>
#include <QVector>
#include <QStringList>

QT_BEGIN_NAMESPACE
class QTcpServer;
class QNetworkSession;
class QTcpSocket;
class QTimer;
QT_END_NAMESPACE

class Server : public QObject
{
Q_OBJECT

public:
Server(QString ipAddress, int port, QObject *parent = 0);

private slots:
void newConnectionSlot();
void sendSlot();

private:
QTcpServer *mTcpServer;
QTcpSocket *mTcpSocket;
QTimer *mSendTimer;


QVector<double> latitude;
QVector<double> longitude;
QVector<double> height;
QString latitudeTest;
QString longitudeTest;
QString heightTest;
QVector<QString> positionTest;
QStringList data;

};

#endif /* SERVER_H_ */


readData.cpp


#include <QFile>
#include <QTextStream>
#include "readdata.h"
#include "QPoint"

void readPathData(QString filename, QVector<double>* latitude, QVector<double>* longitude)
{
QFile file;
file.setFileName(filename);
file.open(QIODevice::ReadOnly);
QByteArray line = file.readLine(); //Read two first lines of the .kml file
line = file.readLine();

while (!file.atEnd()) {
QByteArray line = file.readLine();
if(line[0] != '<')
{
double lon;
double lat;
double hei;

QList<QByteArray> values = line.split(',');

hei = atof(values.at(2).constData());
lat = atof(values.at(1).constData());
lon = atof(values.at(0).constData());

if (latitude)
latitude->append(lat);


if (longitude)
longitude->append(lon);
}
}
file.close();
}



readData.h


#include <QString>
#include <QVector>

#ifndef READDATA
#define READDATA

void readPathData(QString filename, QVector<double>* latitude, QVector<double>* longitude/*, QVector<double>* height*/);

#endif // READDATA


CLIENT
main.cpp


#include <iostream>
#include <QCoreApplication>

#include "client.h"

int main(int argc, char *argv[]){
QCoreApplication app(argc, argv);
QString ipaddress = QString(argv[1]);
int port = atoi(argv[2]);
Client* client = new Client("127.0.0.1", 1234);
int retVal = app.exec();
}



client.cpp


#include "client.h"
#include <iostream>
#include <QTcpSocket>
#include <QSettings>
#include <QDateTime>

Client::Client(QString ipAddress, int port, QObject *parent):
QObject(parent), mTcpSocket(0), mIpAddress(ipAddress), mPort(port)
{
mTcpSocket = new QTcpSocket(this);
connect(mTcpSocket, SIGNAL(readyRead()),
this, SLOT(readSlot()));
connect(mTcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(displayErrorSlot(QAbstractSocket::SocketError )));

std::cout << "Connecting to ip: " << mIpAddress.toStdString() << " port: " << mPort << std::endl;
mTcpSocket->connectToHost(mIpAddress, mPort);
}

void Client::readSlot()
{
static qint64 starttime = QDateTime::currentMSecsSinceEpoch();
static int frames = 0;

qint64 blockSize = 1440000; //in bytes

QDataStream in(mTcpSocket);

if (blockSize == 0) {
if (mTcpSocket->bytesAvailable() < (int)sizeof(quint32))
return;
in >> blockSize;
}

if (mTcpSocket->bytesAvailable() < 38)
return;

QString nextPos;
in >> nextPos;
currentPos = nextPos;

char* data = (char*) malloc(blockSize);
qint64 bytesRead = mTcpSocket->read(data, blockSize);
free(data);
qDebug() << "Data" << data;
qDebug() << "Position" << currentPos;

}

void Client::displayErrorSlot(QAbstractSocket::SocketEr ror socketError)
{
switch (socketError) {
case QAbstractSocket::RemoteHostClosedError:
break;
case QAbstractSocket::HostNotFoundError:
std::cout << "The host was not found. Please check the "
"host name and port settings."<< std::endl;
break;
case QAbstractSocket::ConnectionRefusedError:
std::cout << "The connection was refused by the peer. "
"Make sure the fortune server is running, "
"and check that the host name and port "
"settings are correct."<< std::endl;
break;
default:
std::cout << "The following error occurred: " << mTcpSocket->errorString().toStdString() << std::endl;
break;
}
}



client.h


#ifndef CLIENT_H_
#define CLIENT_H_

#include <QObject>
#include <QAbstractSocket>

QT_BEGIN_NAMESPACE
class QTcpSocket;
QT_END_NAMESPACE

class Client : public QObject
{
Q_OBJECT
public:
Client(QString ipAddress, int port, QObject *parent=0);

private slots:
void readSlot();
void displayErrorSlot(QAbstractSocket::SocketError);

private:
QTcpSocket *mTcpSocket;
QString mIpAddress;
int mPort;
QString currentPos;
};

#endif /* CLIENT_H_ */

yeye_olive
19th May 2015, 15:04
Your code is so broken I wonder where to begin. Here are some of the things I observed:

Server:
main() leaks the Server object (which is bad practice, but may not be noticeable).
The server only sends data to the latest connected client, and does so at a rate growing with the number N of clients that have connected to the server since it started.
The server leaks memory like there is no tomorrow. Every 40/N ms on average, it completely parses the file, appends a new copy of the parsed data to latitude, longitude, positionTest, and data, and then proceeds to send tons of blocks of data to the latest connected client.
I wonder how long the server runs before it runs out of memory.

Client:
main() leaks the Client object (which is bad practice, but may not be noticeable).
readSlot() parses some data it receives according to a different protocol than the one used by the server. It tests whether 1440000 == 0 (I have no idea why). It tricks qDebug() into reading from deallocated memory.

I will stop here because I believe you need to start over. First try to build a very small example with a server that sends one byte to a client.

JorgeQT
19th May 2015, 15:14
Okay, thanks for the answer. I will try to start with something easier. Do you know where can I find an example for that?

yeye_olive
19th May 2015, 15:38
Sure, Qt's networking examples (http://doc.qt.io/qt-5/examples-network.html) are a good place to start. I suggest you focus on one aspect of the problem at a time.

In particular, have a look at the Fortune Server (http://doc.qt.io/qt-5/qtnetwork-fortuneserver-example.html) and Client (http://doc.qt.io/qt-5/qtnetwork-fortuneclient-example.html). These examples are very simple because the connections do not persist: the server accepts a connection, immediately writes some data, closes the socket, and forgets about it. Still, they show how to serialize and deserialize a QString.

Then, maybe, improve on this example by having persistent connections, e.g. by having the server send a simple message whenever a timer ticks. This will teach you how to manage several concurrent client connections in the server (maybe each with its own timer). Or you could set up the QTcpServer so that it never accepts more than one client connection at a time, if this is acceptable to you; that would allow a much simpler design.

After you have done all that, you could focus on the issue of transmitting data gradually read from a file.

wysota
19th May 2015, 17:23
I will stop here because I believe you need to start over. First try to build a very small example with a server that sends one byte to a client.

I will also add that the client repeats a totally broken read pattern where it reads 4 bytes and then forgets them if more data is not available completely desyncing the connection.

Remember that the fortune server and fortune client examples are just examples, do not follow their architecture for any real-world applications, those examples are totally broken when it comes to security and robustness!

JorgeQT
20th May 2015, 09:17
Hi,

Right now I am able to send bytes from the server to the client, but I don't know how I can keep alive the connection. Any suggestions?

wysota
20th May 2015, 09:22
If you want keep-alive for less than the system socket timeout setting (usually at least 10 minutes or so), you don't have to do anything. If you want to support silence for longer periods of times, you will need to set the keep-alive flag on the socket with setSocketOption().

JorgeQT
20th May 2015, 09:28
Thanks,

This is the code to send data from the server to the client. I think I am not closing the connection. Now I am trying to disconnect from the client side.



void Server::sendData()
{
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_0);
out << (quint16)0;

QVector<double> latitude, longitude, height;

readPathData("/home/jorge/Desktop/INStest.kml", &latitude, &longitude, &height);

latitudeTest = QString::number(latitude[0]);
longitudeTest = QString::number(longitude[0]);
heightTest = QString::number(height[0]);
positionTest.append(QString::number(latitude[0]) + " " + QString::number(longitude[0]) + " " + QString::number(height[0])+ "\n");
data << positionTest[0];
out << data.at(qrand() % data.size());
out.device()->seek(0);
out << (quint16)(block.size() - sizeof(quint16));

QTcpSocket *clientConnection = tcpServer->nextPendingConnection();
clientConnection->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
clientConnection->write(block);
}