PDA

View Full Version : using socket descriptor to identify the clients connected to the Threded server



meena
13th May 2010, 14:02
Hi

How to use the socketDescriptor to identify the clients currently connected to threaded server.

thread is created when any client is connected to the server..
void FortuneServer::incomingConnection(int socketDescriptor)
{
FortuneThread *thread = new FortuneThread(socketDescriptor);
..
thread->start();
}

... in run()
{
set the socket Descriptor for the tcpSocket..
connect(this->tcpSocket, SIGNAL(readyRead()), this, SLOT(ready1), Qt::UniqueConnection);
}

ready1()
{
read the request from the clients & serve....)
}

need to write a function which sends some information to all the connected clients...
how to do this..

Thanks

tbscope
13th May 2010, 14:52
To send a message to all clients, you'll need to keep a list of all connected clients.

Why do you want to use threads? Are the clients/server synchronous (blocking) or asynchronous (non-blocking)?
If you do not need synchronous connections, then do not use threads, just keep a list of the client sockets.

Edit:
Ohh... and do not add this line:
connect(this->tcpSocket, SIGNAL(readyRead()), this, SLOT(ready1), Qt::UniqueConnection);
in the run() function of a thread!
Add it to the constructor of your thread, or a function that sets the socket for that thread.

meena
13th May 2010, 15:01
Thanks for reply..
I need Asynchronous communication..
how can i connect multiple clients without using threads..
(My server has SQLite DB connection.. just information.. if it changes the conclusion of using thread or not using thread..)

& How to get the list of all connected clients..?

tbscope
13th May 2010, 15:13
In your server create a list for client connections.
QList<QTcpSocket *> clientConnections;

Then, when you receive an new incomming connection, add the socket to the clientConnections list.
Connect the most useful signals of the client socket to slots in your server. For example, disconnected() and readyRead().

Example:

void YourServer::incomingConnection(int socketDescriptor)
{
QTcpSocket *clientConnection = new QTcpSocket;
clientConnection->setSocketDescriptor(socketDescriptor);

clientConnections->append(clientConnection);

connect(clientConnection, SIGNAL(...), this, SLOT(...));

// send some welcome to your socket (example)
sendWelcome(clientConnection);
}



When you want to send something to all client connections:



void sendToAllConnections(...)
{
foreach(QTcpSocket *clientConnection, clientConnections) {
clientConnection->write(...);
}

etc...
}

meena
14th May 2010, 07:51
Thanks a lot for the valuable suggestions, I will try multiple client connection without using threads.
but using threads it was working fine.. with some run time warnings.. like "QObject: Cannot create children for a parent that is in a different thread. (Parent is FortuneThread(0x23bb7a0), parent's thread is QThread(0x1b166a0), current thread is FortuneThread(0x23bb7a0)" now whenconnect(this->tcpSocket, SIGNAL(readyRead()), this, SLOT(ready1), Qt::UniqueConnection); in the constructor of the thread the runtime warning vanished.. now in the run() i have only
{
while(1)
{
}
}
no other than this if i remove the while().. only first time it reads and write. i want to know the reasons & the logic.. can i ask u to put light on this or suggest me some resources where i will get the good knowledge.

meena
18th May 2010, 14:59
How to pass the list of clientConnections in sendToAllConnections functions

tbscope
18th May 2010, 17:50
You do not, it is already there.
In my example above, when I write
void sendToAllConnections(...)
I really meant:
void YourServer::sendToAllConnections(...)

You add QList<QTcpSocket *> clientConnections; to your server class. Then it is available in every method of that class. Basic C++



class YourServer : public QTcpServer
{
Q_OBJECT

public:
...
void sendToAllConnections(const QString& message);

private:
QList<QTcpSocket *> clientConnections;
}

void YourServer::sendToAllConnections(const QString& message)
{
...
// Be sure to also check if the list isn't empty etc...
}

meena
24th May 2010, 06:47
I have created a GUI project, in server class is i have imported QTcpServer & QTcpSocket. & using the incomingConnection() in this class. but this server is not able to read or write to the client.but there is connection established b/w client & server. few code lines to support this explanation..
server.h
namespace Ui {
class Server;
}

class Server : public QWidget {
Q_OBJECT
public:

protected:
void incomingConnection(int socketDescriptor);

private:
QTcpServer *tcpServer;
QTcpSocket *clientConnection;

private slots:
void Transactions();
};
server.cpp
tcpServer = new QTcpServer(this);
QHostAddress ipadd("..");
tcpServer->listen(ipadd, p.no)

void Server::incomingConnection(int socketDescriptor)
{
clientConnection = new QTcpSocket(this);
clientConnection->setSocketDescriptor(socketDescriptor);
connect(this->clientConnection, SIGNAL(readyRead()), this, SLOT(Transactions()));
clientConnection->write("Hello from Server to client");
}

void Server::Transactions()//to read & write back..
{
char buf[1024];
qint64 lineLength = clientConnection->read(buf, sizeof(buf));
if (lineLength != -1) {

}
}

tbscope
24th May 2010, 08:21
Please take at least a little bit of effort to check your code yourself.
If you do not see your error then I think it's better to start on something easier.

You do not receive data from a client because there is no client.
Connect the incomingConnection signal to your incomingConnection slot (which also should be defined as a slot).

This is VERY basic!

meena
24th May 2010, 12:16
k but
if i declare incomingConnection as a slot it is telling
Object::connect: No such slot QTcpServer::incomingConnection(int) in server.cpp

as in qtcpserver.h this is defined as
protected:
virtual void incomingConnection(int handle);

tbscope
24th May 2010, 12:33
Here you go:
This will be much better, but check the code yourself as I didn't test it.



class YourServer : public QTcpServer
{
Q_OBJECT

public:
YourServer(QObject *parent = 0);
void sendToAllConnections(const QString& message);

private slots:
void slotNewConnection();

private:
QList<QTcpSocket *> clientConnections;
}

YourServer::YourServer(QObject *parent)
: QTcpServer(parent)
{
connect(this, SIGNAL(newConnection()), this, SLOT(slotNewConnection()));
}

void YourServer::slotNewConnection()
{
QTcpSocket *clientConnection;

while (hasPendingConnections()) {
clientConnection = nextPendingConnection();

clientConnections->append(clientConnection);

connect(clientConnection, SIGNAL(...), this, SLOT(...));
}
}

void YourServer::sendToAllConnections(const QString& message)
{
foreach(QTcpSocket *clientConnection, clientConnections) {
clientConnection->write(message.toUtf8());
}
}

meena
25th May 2010, 13:53
Thanks, the code works with bit modifications, for single client.. when many clients are connected there is the problem.. first time when client is connected it communicates(reads.. writes) properly. next one more client is connected server communicates with the second client properly... now after this when again the first client wants to communicate.. Server is not reading the data sent by this client. but the connection is there b/w server & first client.. as it keeps sending the data.(sendToAllConnections() is connected to a timer event).

tbscope
25th May 2010, 17:11
My fault. I should have said this earlier.

You need to use a signal mapper to connect the readyRead signals.
Of, if you do not want to use a signal mapper, use the sender() function to get the socket that is sending the signal.

jackmack
27th January 2011, 10:35
Hi all!

An other question:

All incoming client connections are stored in a list, ok.
Method sendToAllConnections() is also ok.

But how do you remove a connection from the list? This happens if the connection was closed/disconnected.

For example:
3 incoming client, list size = 3. Now the second client is closed by e.g. itself. The list size is also 3, because only a reference was stored. That couses a crash with next sendToAllConnections() call.

I tried to store the clients in a map with clients socketDescriptor as key. But if the QTcpClient::disconnected() is emitted the descriptor is already invalid (-1).

That's strange, I don't know how I can keep valid my list of connected clients.

Any suggestions?

tbscope
27th January 2011, 11:01
http://www.qtcentre.org/wiki/index.php?title=Multi_client_server_without_thread ing


void MultiClientServer::clientDisconnected()
{
QTcpSocket *client = qobject_cast<QTcpSocket *>(sender());

if (!client)
return;

clientConnections.removeAll(client);
client->deleteLater();
}

jackmack
30th January 2011, 05:11
Thanks a lot!

scieck
12th April 2011, 14:21
http://www.qtcentre.org/wiki/index.php?title=Multi_client_server_without_thread ing


void MultiClientServer::clientDisconnected()
{
QTcpSocket *client = qobject_cast<QTcpSocket *>(sender());

if (!client)
return;

clientConnections.removeAll(client);
client->deleteLater();
}

It seems that the QTcpSocket does not have an implementation of operator==(), does anyone know if the removeAll method of QList (which as stated in the docs: "requires the value type to have an implementation of operator==()") can still find (and therefore remove) the passed socket ?
And would the answer also apply to a QSslSocket?

Many Thanks
_andrea

SwanseaLover
14th April 2013, 08:08
hi

how can i write i msg to specific clientConnection which are saved in list of clientConnections.??instead of clientConnection->write("");
is there i way to use value of list to specify a client insted of sending a msg to each incoming connection??

anda_skoa
14th April 2013, 11:01
QList has an index operator and an at() method that both allow you to address a specific element in the list.

Cheers,
_

SwanseaLover
15th April 2013, 10:52
i have tried .at() as following but i got an error:

QTcpSocket *clientConnection = new QTcpSocket;
clientConnection->setSocketDescriptor(socketDescriptor);
clientConnections.append(clientConnection);
QTcpSocket clientConnection0 =clientConnections.at(1);

error:24: error: conversion from ‘QTcpSocket* const’ to non-scalar type ‘QTcpSocket’ requested

Added after 16 minutes:

i tried

clientConnections.at(0)->write("hello");
but i got error index out of range

so how can specify the range in Qlist ,so latter i can use specific index of socket to write msg.

what im trying to do is 1.accept incoming connection in server side
2.keep a list of all connected socket..and do not write() msg immediately after accepting the connection unless pressing push button for example,
can you help me plz

anda_skoa
15th April 2013, 18:48
i have tried .at() as following but i got an error:

QTcpSocket *clientConnection = new QTcpSocket;
clientConnection->setSocketDescriptor(socketDescriptor);
clientConnections.append(clientConnection);
QTcpSocket clientConnection0 =clientConnections.at(1);

error:24: error: conversion from ‘QTcpSocket* const’ to non-scalar type ‘QTcpSocket’ requested


The list contains QTcpSocket* elements, you try to assign to a QTcpSocket variable.



QTcpSocket *clientConnection0 =clientConnections.at(1);

Access to the second entry in list clientConnections



i tried

clientConnections.at(0)->write("hello");
but i got error index out of range


Meaning the list is empty.
Check the index you attempt to use against QList::count() to see it it is valid.

The index you are using has to be >= 0 and < QList::count()

Cheers,
_

SwanseaLover
16th April 2013, 10:12
it's clear now :D
:o
Many Thanks

SwanseaLover
17th April 2013, 08:30
hi again
i'm trying to access clientConnections according to socketDescriptor insted of index inorder to use write();
i was trying to comper the valuse inserted in the list according to socketDescriptor obtained

so when server accepted a new connection , i debuge socket discrptor


void Server::incomingConnection(int socketDescriptor)
{

QTcpSocket *clientConnection = new QTcpSocket;
clientConnection->setSocketDescriptor(socketDescriptor);
clientConnections.append(clientConnection);

qDebug()<<"socket id :"<<socketDescriptor; ......out put 23 for example

}


so when compering latter :
Server server;
QTcpSocket *checkSocket=new QTcpSocket();
checkSocket->setSocketDescriptor(23)
qDebug()<<server.clientConnections.value(0)<<checkSocket; ....it is first connection at index 0

out put:
they are difffernt
QTcpSocket(0x8972438) QTcpSocket(0x896d0e8)

anda_skoa
17th April 2013, 09:52
QTcpSocket *checkSocket=new QTcpSocket();

You create a new QTcpSocket instance, of course its pointer will be different.

If you want to access the socket by socket descriptor, then better us a QHash instead of a list, using the socket descriptor as the key



QHash<int, QTcpSocket*> clientConnections;



clientConnections.insert(socketDescriptor, clientConnection);


Retrieval


QTcpSocket *socket = clientConnections.value(socketDescriptor);


Any reason you want to use the socketDescriptor as the identifier? Where do you store that that you cannot store the pointer to the QTcpSocket directly?

Cheers,
_