PDA

View Full Version : QTcpServer & QTcpSocket questions...



jxmot
23rd April 2008, 20:29
Greetings,

First, great site... very helpful. Second, I'm a QT newbie but have been programming for 25 years.

I'm having some difficulty getting a simple QTcpServer & QTcpSocket working. It's just a console app that acts as either a server or a client. It's base on the Fortune demo, without the GUI code. I've ran the fortune demo on the same PC where I'm writing the app and it works just fine so I know the problem is related to something I've done incorrectly.

I've already searched this forum for answers but I haven't found anything that seems to apply to this problem. So any help is appreciated! Thanks in advance!

Here's all of the code (main.cpp, ipcomm.h, ipcomm.cpp - built w/ MSVS 2005) -

main.cpp:


#include <QtCore/QCoreApplication>
#include "IPComm.h"

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);

// select "server" or "client"
if(argc > 1)
{
printf("instan ipcomm\n");
IPComm ipcomm;
ipcomm.init();

if(strcmp((const char *)argv[1], "s") == 0)
{
// server
printf("starting server\n");
ipcomm.server();
}
else
{
if(strcmp((const char *)argv[1], "c") == 0)
{
// client
printf("starting client\n");
if(argc > 2)
{
int port = atoi((const char *)argv[1]);
ipcomm.client(port);
// not sure if this is correct, seems
// to be the only way for this func
// to get called.
ipcomm.requestNewData();
}
else
printf("Must supply port for client\n");
}
}
}
return a.exec();
}



ipcomm.h:


#pragma once

#include <QtCore/QCoreApplication>
#include <QtNetwork>
#include <QTcpSocket>
#include <QHostAddress>

class QTcpServer;
class QTcpSocket;
class QHostAddress;


enum {
TCP_NONE = 0,
TCP_SERVER,
TCP_CLIENT
};

class IPComm : public QObject
{

Q_OBJECT

public:
IPComm(void);
~IPComm(void);


QTcpServer *tcpServer;
QStringList fortunes;

QTcpSocket *tcpClient;
QString currentFortune;
quint16 blockSize;


int tcpType;
quint16 tcpPort;

void init(void);

void server(void);
void client(int port);

public slots:
void requestNewData(void);

private slots:
void sendData(void);
void readData(void);
void displayError(QAbstractSocket::SocketError socketError);

};



ipcomm.cpp:


include "IPComm.h"
#include <string>

IPComm::IPComm(void)
{
}

IPComm::~IPComm(void)
{
}

void IPComm::init(void)
{
tcpServer = NULL;
tcpClient = NULL;
tcpType = TCP_NONE;

// testing data
fortunes << tr("You've been leading a dog's life. Stay off the furniture.")
<< tr("You've got to think about tomorrow.")
<< tr("You will be surprised by a loud noise.")
<< tr("You will feel hungry again in another hour.")
<< tr("You might have mail.")
<< tr("You cannot kill time without injuring eternity.")
<< tr("Computers are not intelligent. They only think they are.");
}

void IPComm::server(void)
{
if(tcpType == TCP_NONE)
{
tcpServer = new QTcpServer(this);
tcpType = TCP_SERVER;

// trying out different methods for setting the address
// if(!tcpServer->listen(QHostAddress::LocalHost))
QHostAddress qhl("10.3.23.27");
if(!tcpServer->listen(qhl))
printf("Unable to start the server: %s", tcpServer->errorString());
else
{
if(tcpServer->isListening())
{
QHostAddress qhost = tcpServer->serverAddress();
std::string qh = qhost.toString().toStdString();
printf("The server address is %s\n", (char *)qh.c_str());
printf("The server port is %d\n", tcpServer->serverPort());

connect(tcpServer, SIGNAL(newConnection()), this, SLOT(sendData()));
}
else
printf("we're NOT listening!!\n");
}
printf("server() - done\n");
}
}

void IPComm::client(int port)
{
if(tcpType == TCP_NONE)
{
tcpClient = new QTcpSocket(this);
tcpType = TCP_CLIENT;

tcpPort = port;

connect(tcpClient, SIGNAL(readyRead()), this, SLOT(readData()));
connect(tcpClient, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(displayError(QAbstractSocket::SocketError)));

printf("client() - done\n");
}
}

void IPComm::readData()
{
printf("readData() - begin\n");

QDataStream in(tcpClient);
//in.setVersion(QDataStream::Qt_4_0);

if (blockSize == 0)
{
if (tcpClient->bytesAvailable() < (int)sizeof(quint16))
return;

in >> blockSize;
}

if (tcpClient->bytesAvailable() < blockSize)
return;

QString nextFortune;
in >> nextFortune;

if (nextFortune == currentFortune)
{
printf("readData() - requestNewData\n");
QTimer::singleShot(0, this, SLOT(requestNewData()));
return;
}

currentFortune = nextFortune;
std::string tmp = currentFortune.toStdString();
printf("readData(): %s\n", (char *)(tmp.c_str()));
}

void IPComm::requestNewData()
{
printf("requestNewData() - begin\n");

blockSize = 0;
tcpClient->abort();

QString servIP = "10.3.23.27";
int servPO = tcpPort;

tcpClient->connectToHost(servIP, servPO);

printf("requestNewData() - done\n");
}


void IPComm::sendData()
{
printf("sendData() - begin\n");

QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_0);
out << (quint16)0;
out << fortunes.at(qrand() % fortunes.size());
out.device()->seek(0);
out << (quint16)(block.size() - sizeof(quint16));

QTcpSocket *clientConnection = tcpServer->nextPendingConnection();
connect(clientConnection, SIGNAL(disconnected()),
clientConnection, SLOT(deleteLater()));

clientConnection->write(block);
clientConnection->disconnectFromHost();

printf("sendData() - done\n");
}


void IPComm::displayError(QAbstractSocket::SocketError socketError)
{
switch (socketError)
{
case QAbstractSocket::RemoteHostClosedError:
printf("The connection was closed by the host.\n");
break;

case QAbstractSocket::HostNotFoundError:
printf("The host was not found. Please check the host name and port settings.\n");
break;

case QAbstractSocket::ConnectionRefusedError:
printf("The connection was refused by the peer.\n");
break;

default:
std::string err = tcpServer->errorString().toStdString();
printf("the following error occurred: %s\n", (char *)err.c_str());
break;
}
}

McToo
24th April 2008, 17:10
Hi

You don't say what problems you're having. If it's a read/write problem, I think your problem may lie in the following areas:

In sendData() you initialise a QByteArray with the data you intend to send, then use write(block) to send it 'over the wire'.

In readData() you initialise QDataStream with the client socket, but in my experience you need to cast your variables to references to allow them to be written to i.e.:


QDataStream in(tcpClient);
in >> (quint16&) blockSize;

Same for the read of fortune - should be
in >> (QString&) nextFortune;

Mixing the QByteArray/write and QDataStream >> methods together doesn't seem like a good idea in my view - stick to one or t'other!

They are the things that jumped out at me after looking at your code.

Mc

jxmot
24th April 2008, 22:38
Oops! All that I and didn't specifiy the problem (I must be getting "old"). Anyways, I can't get the app to connect. I run the exe twice, once as a "server" and again as the "client".

As an experiment I split the ipcomm class into two, ipserver and ipclient and then built 2 separate exe's. That works. The connection is made and the data is sent. However my preference is to create a single class to handle both the client and server functionality.

thanks!