PDA

View Full Version : Help with a simple client programe



QuTe
25th October 2007, 13:54
Hi all,

I'm coding a simple client-server communication programe, wherein I require to send a struct data to server. Is it possible to send the struct as a single packet to the server??
if yes, then how to do it?

any help will be apprecated.

regards

DeepDiver
25th October 2007, 14:08
Hi,

a good starting point for this is Qt Network Examples (http://doc.trolltech.com/4.3/examples.html#network).
For more detailed information have look at Qt Network Module (http://doc.trolltech.com/4.3/qtnetwork.html).

For serialization of data structures have a look at QDataStream (http://doc.trolltech.com/4.3/qdatastream.html).


For further help - just ask!

Good luck

Tom

QuTe
25th October 2007, 16:08
will not that serialization of the structure data make it different packets, if I'll use QDataStream? , b'coz all the server is looking for is a single packet, which consists of certain header along with data like username.

kindly throw some light on it pls.

Thanks

DeepDiver
25th October 2007, 16:20
What do you mean by "single packet"?

QDataStream will help you to keep your code base small and provides an easy-to-use way to handle serialization.

QDataStream will help you to avoid nasty parsing and/or byte counting stuff.

QuTe
25th October 2007, 16:57
by 'single packet' I meant to say that, the packet structure consist of header, a key, and the data -- which is username. Now when we're going to use QDataStream, we'll be using "<<" operator to send each and every variable of the struct. so my query is will it send differently of just as serially as it is there, in the QDataStream, so that the server won't receive the struct in different format altogether at its end.

Thanks :)

DeepDiver
25th October 2007, 17:13
... Now when we're going to use QDataStream, we'll be using "<<" operator to send each and every variable of the struct.
...

You can stream a whole struct/class to QDataStream by defining stream operators for the struct/class.
This is a little bit nicer than every time streaming the struct members.

Good luck,

Tom

Here some pseudo-code to show what I mean:



class SomeClass
{
...
private:
int _mSomeInt;
QString _mSomeString;

friend Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const SomeClass &);
friend Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, SomeClass &);

};




QDataStream &operator<<(QDataStream &out, const SomeClass &c)
{
return out << (quint32)(c._mSomeInt) << c._mSomeString;
}

QDataStream &operator>>(QDataStream &in, SomeClass &c)
{
quint32 i;
in >> i;
c._mSomeInt = i;
in >> c._mSomeString;
return in;
}

QuTe
26th October 2007, 07:24
Hi Tom
Thanks for the helpful suggestions. But when I used the my own operator "<<" definition, its not detecting it somehow! i don't know whats wrong, but its throwing the error that "no match ' ' found", for the operator I'm using.
I've declared the QDatastream operator the same way you've shown in the snippet above. but it still doesn't work for me.

pls help.

Thanks

DeepDiver
26th October 2007, 09:07
Attach the code and we can have a look!

Tom

QuTe
26th October 2007, 09:48
ok here you go then:

header file:

#ifndef CLIENTSOCKET_H
#define CLIENTSOCKET_H

#include <QTcpSocket>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QTextDocument>
#include <QLineEdit>
#include <QLabel>
#include <QPushButton>
#include <QTextStream>
#include <qglobal.h>
#include <QDataStream>


struct clientPktStruct {
QString pktString;
qint32 size_of_pkt;
qint8 key;
QString uName;
};


class Client : public QWidget
{
Q_OBJECT
public:
Client(QWidget *parent=0);


~Client()
{
}

private slots:
void closeConnection();
void sendToServer();
void socketReadyRead();
void socketConnected();
void socketConnectionClosed();
void socketClosed();
void displayError( QAbstractSocket::SocketError );

private:
QPushButton *okay;
QPushButton *cancel;
QString strnglist;
QString newChallengeString;
QTcpSocket *socket;
QFile *infoText;
QDataStream Debug;
QLabel *userNameLabel;
QLabel *userPasswdLabel;
QLineEdit *userNameText;
QLineEdit *userPasswdText;
struct clientPktStruct clientPkt;

quint16 port;
quint16 blockSize;
friend Q_CORE_EXPORT QDataStream &operator<< (QDataStream &, const struct clientPktStruct &);
};

#endif

and the cpp file:

#include <QtGui>
#include <QLineEdit>
#include <QBoxLayout>
#include <QHostAddress>

#include "clientSocket.h"


Client::Client(QWidget *parent)
:QWidget(parent)
{

// GUI layout
QVBoxLayout *mainLayout = new QVBoxLayout(this);
QHBoxLayout *hb = new QHBoxLayout;

QGridLayout *labelLayout = new QGridLayout;
userNameLabel = new QLabel(tr("UserName:"), this);
userPasswdLabel = new QLabel(tr("Password:"), this);
userNameText = new QLineEdit(this);
userPasswdText = new QLineEdit(this);
userPasswdText->setEchoMode(QLineEdit::Password);
labelLayout->addWidget(userNameLabel, 0, 0);
labelLayout->addWidget(userNameText, 0, 1);
labelLayout->addWidget(userPasswdLabel, 1, 0);
labelLayout->addWidget(userPasswdText, 1, 1);

okay = new QPushButton( tr("ok") , this );
cancel = new QPushButton( tr("cancel") , this );

hb->addWidget(okay);
hb->addWidget(cancel);

mainLayout->addLayout(labelLayout);
mainLayout->addStretch(1);
mainLayout->addLayout(hb);
setLayout(mainLayout);
connect( okay, SIGNAL(clicked()), SLOT(sendToServer()) );
connect( cancel, SIGNAL(clicked()), qApp, SLOT(quit()) );

// create the socket and connect various of its signals
QHostAddress host;
host.setAddress("203.187.156.70");
port = 5000;
socket = new QTcpSocket( this );
connect( socket, SIGNAL(connected()),
SLOT(socketConnected()) );
connect( socket, SIGNAL(connectionClosed()),
SLOT(socketConnectionClosed()) );
connect( socket, SIGNAL(readyRead()),
SLOT(socketReadyRead()) );
connect( socket, SIGNAL(error(QAbstractSocket::SocketError)),
SLOT(displayError(QAbstractSocket::SocketError)) );

// connect to the server
clientPkt.pktString = "ISHR1.00";
clientPkt.key = 101;

socket->connectToHost( host, port );
}

........
........

void Client::sendToServer()
{
// write to the server
clientPkt.uName = userNameText->text();
clientPkt.size_of_pkt = sizeof(clientPkt);

QDataStream sendData(socket);
sendData.setVersion(QDataStream::Qt_4_0);

/* this is where the operator will be used */
sendData<<clientPkt;

userNameText->setText( "" );
okay->setEnabled(false);
}

..........
..........
.........


/* operator for datastreaming a structure field */
QDataStream &operator<< (QDataStream &sendPkt, const struct clientPktStruct &CPkt)
{
return sendPkt <<CPkt.pktString<<CPkt.size_of_pkt<<CPkt.key<<CPkt.uName;
}


after compilation the compiler throw the error::
error: no match for 'operator <<' in 'sendData <<Client::clientPkt'

QuTe
26th October 2007, 10:02
oops my bad!

I just realised what I did :o, I should have implemented the 'operator<<' before utilising it in the program. I mistakenly put it later.

nevermind sry about that.

Thanks alot for the help Tom :)

Regards

QuTe
29th October 2007, 04:50
Now, everything is working fine, except the fact that, my server is not being able to recognize the protocol which we use( we put the a string to recognize the packets in its header). and I checked with the server data and I found that, actually the server is getting '0' s ( zeros) in between each of the character data I'm sending!! and btw I'm sending it using QDataStream.
And I also tried with QByteArray, and well it works bit fine with it, as compared to QDataStream, but in QByteArray as well, I'm facing a problem, which is, my server doesn't get the size of the packet( which is one of the members of the packet structure which I'm sending from here)
Now is there any other simple way to send data packets to server without getting the data manipulated while sending using Qt APIs???

pls help

Regards

jacek
31st October 2007, 21:41
I checked with the server data and I found that, actually the server is getting '0' s ( zeros) in between each of the character data I'm sending!!
By default Qt sends strings in UTF-16 --- that's why each character is encoded using two bytes.


and btw I'm sending it using QDataStream.
QDataStream uses its own protocol for serialization, see here (http://doc.trolltech.com/4.3/datastreamformat.html).


Now is there any other simple way to send data packets to server without getting the data manipulated while sending using Qt APIs???
Use QDataStream::writeRawData(), QDataStream::writeBytes() or QIODevice::write().