PDA

View Full Version : QLocalServer with multiple clients — proper handling



indiocolifa
27th July 2010, 07:07
I'm trying to make IPC work between one server to accept requests from multiple clients with Qt 4.6. All is working, except that the underlying named pipes are not being closed, making Qt to emit the maximum handle reached message (62).

Since I want to accept several client connections, I handle newConnections to the QLocalServer class as follows:



void ServerImpl::onNewConnection()
{
QLocalSocket * plsocket = _server->nextPendingConnection();
SocketHandler* skh = new SocketHandler(plsocket, this, this);
connect(plsocket, SIGNAL(readyRead()), skh, SLOT(socketReadyRead()));
connect(plsocket, SIGNAL(error(QLocalSocket::LocalSocketError)), skh,
SLOT(onError(QLocalSocket::LocalSocketError)));
connect(plsocket, SIGNAL(disconnected()), skh, SLOT(disconnected()));
}


Since every time I get a new connection the QLocalSocket pointer received from QLocalServer::nextPendingConnection() is overwritten, I manage the data requests through the SocketHandler class, which of course encapsulates a QLocalSocket class:



void SocketHandler::socketReadyRead()
{
QDataStream in(_ps);
in.setVersion(QDataStream::Qt_4_5);

forever
{
if (_blocksize == 0)
{
if (_ps->bytesAvailable() < sizeof(blocksize_t))
return;

in >> _blocksize;
}

// We need more data?
if (_ps->bytesAvailable() < _blocksize)
return;

_srv->ReadRequest(in);

// CHECK: Discard remaining blocks
_blocksize = 0;
}
}



Here's the class declaration:


class SocketHandler : public QObject
{
Q_OBJECT

public:
SocketHandler(QLocalSocket* ps, ServerImpl* srv, QObject* parent = 0) :
QObject(parent), _ps(ps), _blocksize(0), _srv(srv) { };

virtual ~SocketHandler() {};

public slots:
void socketReadyRead();
void onError(QLocalSocket::LocalSocketError);
void disconnected();

private:

QLocalSocket* _ps;
blocksize_t _blocksize;
ServerImpl* _srv;
};


The problem, as stated above, is that I can't disconnect from server at client request. I tried QLocalSocket::close, QLocalSocket::disconnectFromServer without luck.

Should I go with a multithreaded solution? (I think it won't solve the problem).

Another solution I'm thinking is to offer a 1:1 QLocalServer<-->QLocalSocket IPC mechanism, instead of trying to handle 1:N.

Thanks in advance.

tbscope
27th July 2010, 10:16
Create a QLocalServer
Inside the server, create a list of sockets (to keep track of them)
Connect a slot to the newConnection() signal
In that slot, go through the pending connections and add them to the list.
Connect slots to the most important signals of the socket (like disconnected(), readyRead() etc... This can be done via a QSignalMapper
Implement those slots (example, when disconnected, take the socket out of the list)

That's it.

indiocolifa
27th July 2010, 22:35
I think your approach is well thought, altough I don't find the difference with my multiple instances of a handler class (SocketHandler) except that it's not a socket (it does not inherit QLocalSocket) but QLocalSocket is composited as a member variable.

I believe it's not related to the disconnection (and pipe-handle leaking) problem, but who cares, I will try your idea.

indiocolifa
27th July 2010, 23:45
I implemented your solution, but I still keep getting pipe handles not closed.

For each connection, Qt creates the following named pipes:


\Device\NamedPipe\Win32Pipes.00001490.0000000X
\Device\NamedPipe\<SERVER_KEY>

The second that includes the server key in the pipe name is the type of pipe handles that are not closing.

May be it's an error in my client.
When my client tries to shutdown the connection, the socket error slot signals, with:

QLocalSocketPrivate::completeAsyncRead: Connection error

My client application calls _socket->disconnectFromServer() in the aboutToQuit() handler slot (prior to app quitting).

I related the problem to the eventloop not already responding on the aboutToQuit(), but I tried on other program sections, when the event loop is well alive, and it didn't work. Nevertheless, sockets will get deleted on clean program close, so I think I should not bother manually disconnecting.

indiocolifa
28th July 2010, 00:01
:)

Fixed by letting the server-side closing the socket on disconnection signal. The client just does not nothing, just waits the server to close and delete the QLocalSocket pointer on disconnection.

Thanks, anyway.