I took threaded fortune server example 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>
{
Q_OBJECT
public:
protected:
void incomingConnection ( int socketDescriptor );
private slots:
signals:
};
#endif
#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
To copy to clipboard, switch view to plain text mode
server.cpp:
#include "server.h"
#include "serverthread.h"
{
}
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() ) );
thread->start();
}
{
ServerThread* thread = static_cast<ServerThread*> ( sender() );
emit toClient ( data );
}
#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 ) ) );
}
To copy to clipboard, switch view to plain text mode
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
);
public slots:
private slots:
void socketDisconnected();
void receiveMessage();
void threadStarted();
private:
int socketDescriptor;
quint16 blockSize;
};
#endif
#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
To copy to clipboard, switch view to plain text mode
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()
{
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()
{
if ( blockSize == 0 )
{
if ( client->bytesAvailable() < ( int ) sizeof ( quint16 ) )
return;
in >> blockSize;
}
if ( client->bytesAvailable() < blockSize )
return;
in >> tmp;
str
= QString::fromUtf8 ( qUncompress
( tmp
) );
blockSize = 0;
emit fromClient ( createQByteArray ( str ) ); //pošljemo vsem ostalim clientom povezanim na server
}
{
out << ( quint16 ) 0;
out << qCompress ( str.toUtf8(),9 );
out.device()->seek ( 0 );
out << ( quint16 ) ( block.size() - sizeof ( quint16 ) );
return block;
}
{
client->write ( data );
}
#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 );
}
To copy to clipboard, switch view to plain text mode
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
Bookmarks