frido
1st April 2009, 13:04
I took threaded fortune server example (http://doc.trolltech.com/4.5/network-threadedfortuneserver.html) for experimenting with tcp socket communication.
The idea is to make a server that will accept many clients. When a connected client sends message to server, the server would sent this message to all other connected clients.
Here is the code so far:
server.h
#ifndef SERVER_H
#define SERVER_H
#include <QStringList>
#include <QTcpServer>
class Server : public QTcpServer
{
Q_OBJECT
public:
Server ( QObject *parent = 0 );
protected:
void incomingConnection ( int socketDescriptor );
private slots:
void fromClient(QByteArray data);
signals:
void toClient(QByteArray data);
};
#endif
server.cpp:
#include "server.h"
#include "serverthread.h"
Server::Server ( QObject *parent )
: QTcpServer ( parent )
{
listen ( QHostAddress::Any, 8888 );
}
void Server::incomingConnection ( int socketDescriptor )
{
ServerThread *thread = new ServerThread ( socketDescriptor, this );
connect ( thread, SIGNAL ( finished() ), thread, SLOT ( deleteLater() ) );
connect ( thread, SIGNAL ( started() ), thread, SLOT ( threadStarted() ) );
connect ( thread, SIGNAL ( fromClient ( QByteArray ) ), this, SLOT ( fromClient ( QByteArray ) ) );
connect ( this, SIGNAL ( toClient ( QByteArray ) ), thread, SLOT ( toClient ( QByteArray ) ) );
thread->start();
}
void Server::fromClient ( QByteArray data )
{
ServerThread* thread = static_cast<ServerThread*> ( sender() );
disconnect ( this, SIGNAL ( toClient ( QByteArray ) ), thread, SLOT ( toClient ( QByteArray ) ) );
emit toClient ( data );
connect ( this, SIGNAL ( toClient ( QByteArray ) ), thread, SLOT ( toClient ( QByteArray ) ) );
}
serverthread.h:
#ifndef SERVERTHREAD_H
#define SERVERTHREAD_H
#include <QThread>
#include <QTcpSocket>
class ServerThread : public QThread
{
Q_OBJECT
public:
ServerThread ( int socketDescriptor, QObject *parent );
~ServerThread ();
void run();
signals:
void error ( QTcpSocket::SocketError socketError );
void fromClient(QByteArray data);
public slots:
void toClient(QByteArray data);
private slots:
void socketDisconnected();
void receiveMessage();
void threadStarted();
private:
int socketDescriptor;
QTcpSocket* client;
quint16 blockSize;
QByteArray createQByteArray(QString str);
};
#endif
serverthread.cpp
#include "serverthread.h"
#include <QtNetwork>
ServerThread::ServerThread ( int socketDescriptor, QObject *parent )
: QThread ( parent ), socketDescriptor ( socketDescriptor )
{
blockSize = 0;
}
ServerThread::~ServerThread ( )
{
}
void ServerThread::run()
{
exec();
}
void ServerThread::socketDisconnected()
{
quit();
}
void ServerThread::threadStarted()
{
client = new QTcpSocket(this);
connect ( client, SIGNAL ( disconnected() ),
this, SLOT ( socketDisconnected() ) );
connect ( client, SIGNAL ( readyRead() ),
this, SLOT ( receiveMessage() ) );
if ( !client->setSocketDescriptor ( socketDescriptor ) )
{
emit error ( client->error() );
return;
}
}
void ServerThread::receiveMessage()
{
QDataStream in ( client );
in.setVersion ( QDataStream::Qt_4_0 );
if ( blockSize == 0 )
{
if ( client->bytesAvailable() < ( int ) sizeof ( quint16 ) )
return;
in >> blockSize;
}
if ( client->bytesAvailable() < blockSize )
return;
QString str;
QByteArray tmp;
in >> tmp;
str = QString::fromUtf8 ( qUncompress ( tmp ) );
blockSize = 0;
emit fromClient ( createQByteArray ( str ) ); //pošljemo vsem ostalim clientom povezanim na server
}
QByteArray ServerThread::createQByteArray ( QString str )
{
QByteArray block;
QDataStream out ( &block, QIODevice::WriteOnly );
out.setVersion ( QDataStream::Qt_4_0 );
out << ( quint16 ) 0;
out << qCompress ( str.toUtf8(),9 );
out.device()->seek ( 0 );
out << ( quint16 ) ( block.size() - sizeof ( quint16 ) );
return block;
}
void ServerThread::toClient ( QByteArray data )
{
client->write ( data );
}
Everithing works well if client sends one message. But if i try to send let say 1000 messages (in for loop), other clients don't receive all messages but random noumber of them. Also all clients don't receive same number of messages.
Any suggestions?
tnx
The idea is to make a server that will accept many clients. When a connected client sends message to server, the server would sent this message to all other connected clients.
Here is the code so far:
server.h
#ifndef SERVER_H
#define SERVER_H
#include <QStringList>
#include <QTcpServer>
class Server : public QTcpServer
{
Q_OBJECT
public:
Server ( QObject *parent = 0 );
protected:
void incomingConnection ( int socketDescriptor );
private slots:
void fromClient(QByteArray data);
signals:
void toClient(QByteArray data);
};
#endif
server.cpp:
#include "server.h"
#include "serverthread.h"
Server::Server ( QObject *parent )
: QTcpServer ( parent )
{
listen ( QHostAddress::Any, 8888 );
}
void Server::incomingConnection ( int socketDescriptor )
{
ServerThread *thread = new ServerThread ( socketDescriptor, this );
connect ( thread, SIGNAL ( finished() ), thread, SLOT ( deleteLater() ) );
connect ( thread, SIGNAL ( started() ), thread, SLOT ( threadStarted() ) );
connect ( thread, SIGNAL ( fromClient ( QByteArray ) ), this, SLOT ( fromClient ( QByteArray ) ) );
connect ( this, SIGNAL ( toClient ( QByteArray ) ), thread, SLOT ( toClient ( QByteArray ) ) );
thread->start();
}
void Server::fromClient ( QByteArray data )
{
ServerThread* thread = static_cast<ServerThread*> ( sender() );
disconnect ( this, SIGNAL ( toClient ( QByteArray ) ), thread, SLOT ( toClient ( QByteArray ) ) );
emit toClient ( data );
connect ( this, SIGNAL ( toClient ( QByteArray ) ), thread, SLOT ( toClient ( QByteArray ) ) );
}
serverthread.h:
#ifndef SERVERTHREAD_H
#define SERVERTHREAD_H
#include <QThread>
#include <QTcpSocket>
class ServerThread : public QThread
{
Q_OBJECT
public:
ServerThread ( int socketDescriptor, QObject *parent );
~ServerThread ();
void run();
signals:
void error ( QTcpSocket::SocketError socketError );
void fromClient(QByteArray data);
public slots:
void toClient(QByteArray data);
private slots:
void socketDisconnected();
void receiveMessage();
void threadStarted();
private:
int socketDescriptor;
QTcpSocket* client;
quint16 blockSize;
QByteArray createQByteArray(QString str);
};
#endif
serverthread.cpp
#include "serverthread.h"
#include <QtNetwork>
ServerThread::ServerThread ( int socketDescriptor, QObject *parent )
: QThread ( parent ), socketDescriptor ( socketDescriptor )
{
blockSize = 0;
}
ServerThread::~ServerThread ( )
{
}
void ServerThread::run()
{
exec();
}
void ServerThread::socketDisconnected()
{
quit();
}
void ServerThread::threadStarted()
{
client = new QTcpSocket(this);
connect ( client, SIGNAL ( disconnected() ),
this, SLOT ( socketDisconnected() ) );
connect ( client, SIGNAL ( readyRead() ),
this, SLOT ( receiveMessage() ) );
if ( !client->setSocketDescriptor ( socketDescriptor ) )
{
emit error ( client->error() );
return;
}
}
void ServerThread::receiveMessage()
{
QDataStream in ( client );
in.setVersion ( QDataStream::Qt_4_0 );
if ( blockSize == 0 )
{
if ( client->bytesAvailable() < ( int ) sizeof ( quint16 ) )
return;
in >> blockSize;
}
if ( client->bytesAvailable() < blockSize )
return;
QString str;
QByteArray tmp;
in >> tmp;
str = QString::fromUtf8 ( qUncompress ( tmp ) );
blockSize = 0;
emit fromClient ( createQByteArray ( str ) ); //pošljemo vsem ostalim clientom povezanim na server
}
QByteArray ServerThread::createQByteArray ( QString str )
{
QByteArray block;
QDataStream out ( &block, QIODevice::WriteOnly );
out.setVersion ( QDataStream::Qt_4_0 );
out << ( quint16 ) 0;
out << qCompress ( str.toUtf8(),9 );
out.device()->seek ( 0 );
out << ( quint16 ) ( block.size() - sizeof ( quint16 ) );
return block;
}
void ServerThread::toClient ( QByteArray data )
{
client->write ( data );
}
Everithing works well if client sends one message. But if i try to send let say 1000 messages (in for loop), other clients don't receive all messages but random noumber of them. Also all clients don't receive same number of messages.
Any suggestions?
tnx