Reworked the multi-threaded RPC server/connection architecture into a worker-thread arch as reccomended by Qt

This commit is contained in:
Srivats P. 2014-05-17 18:45:02 +05:30
parent 1a6b23e31d
commit b470ed84bb
6 changed files with 75 additions and 94 deletions

View File

@ -3,5 +3,5 @@ CONFIG += qt staticlib
QT += network QT += network
DEFINES += HAVE_REMOTE DEFINES += HAVE_REMOTE
LIBS += -lprotobuf LIBS += -lprotobuf
HEADERS += rpcserver.h rpcthread.h pbrpccontroller.h pbrpcchannel.h pbqtio.h HEADERS += rpcserver.h rpcconn.h pbrpccontroller.h pbrpcchannel.h pbqtio.h
SOURCES += rpcserver.cpp rpcthread.cpp pbrpcchannel.cpp SOURCES += rpcserver.cpp rpcconn.cpp pbrpcchannel.cpp

View File

@ -1,5 +1,5 @@
/* /*
Copyright (C) 2010 Srivats P. Copyright (C) 2010, 2014 Srivats P.
This file is part of "Ostinato" This file is part of "Ostinato"
@ -20,6 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
#ifndef _PB_RPC_CONTROLLER_H #ifndef _PB_RPC_CONTROLLER_H
#define _PB_RPC_CONTROLLER_H #define _PB_RPC_CONTROLLER_H
#include <google/protobuf/message.h>
#include <google/protobuf/service.h> #include <google/protobuf/service.h>
class QIODevice; class QIODevice;

View File

@ -17,28 +17,24 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/> along with this program. If not, see <http://www.gnu.org/licenses/>
*/ */
#include "rpcthread.h" #include "rpcconn.h"
#include "pbqtio.h" #include "pbqtio.h"
#include "pbrpccommon.h" #include "pbrpccommon.h"
#include "pbrpccontroller.h"
#include <google/protobuf/message.h> #include <google/protobuf/message.h>
#include <google/protobuf/descriptor.h> #include <google/protobuf/descriptor.h>
#include <google/protobuf/service.h> #include <google/protobuf/service.h>
#include <google/protobuf/io/zero_copy_stream_impl.h> #include <google/protobuf/io/zero_copy_stream_impl.h>
#include "pbrpccontroller.h" // FIXME: move up the order and fix warnings
#include <QHostAddress> #include <QHostAddress>
#include <QTcpSocket> #include <QTcpSocket>
#include <qendian.h> #include <qendian.h>
RpcThread::RpcThread( RpcConnection::RpcConnection(int socketDescriptor,
int socketDescriptor, ::google::protobuf::Service *service)
::google::protobuf::Service *service, : socketDescriptor(socketDescriptor),
QObject *parent)
: QThread(parent),
socketDescriptor(socketDescriptor),
service(service) service(service)
{ {
inStream = NULL; inStream = NULL;
@ -46,18 +42,29 @@ RpcThread::RpcThread(
isPending = false; isPending = false;
pendingMethodId = -1; // don't care as long as isPending is false pendingMethodId = -1; // don't care as long as isPending is false
moveToThread(this);
} }
RpcThread::~RpcThread() RpcConnection::~RpcConnection()
{ {
qDebug("destroying connection to %s: %d",
clientSock->peerAddress().toString().toAscii().constData(),
clientSock->peerPort());
// If still connected, disconnect
if (clientSock->state() != QAbstractSocket::UnconnectedState) {
clientSock->disconnectFromHost();
clientSock->waitForDisconnected();
}
delete inStream;
delete outStream;
delete clientSock;
} }
void RpcThread::run() void RpcConnection::start()
{ {
clientSock = new QTcpSocket; clientSock = new QTcpSocket;
//qDebug("clientSock = %p, %p", clientSock, this->clientSock);
if (!clientSock->setSocketDescriptor(socketDescriptor)) { if (!clientSock->setSocketDescriptor(socketDescriptor)) {
qWarning("Unable to initialize TCP socket for incoming connection"); qWarning("Unable to initialize TCP socket for incoming connection");
return; return;
@ -67,28 +74,21 @@ void RpcThread::run()
clientSock->peerAddress().toString().toAscii().constData(), clientSock->peerAddress().toString().toAscii().constData(),
clientSock->peerPort()); clientSock->peerPort());
inStream = new google::protobuf::io::CopyingInputStreamAdaptor( inStream = new google::protobuf::io::CopyingInputStreamAdaptor(
new PbQtInputStream(clientSock)); new PbQtInputStream(clientSock));
inStream->SetOwnsCopyingStream(true); inStream->SetOwnsCopyingStream(true);
outStream = new google::protobuf::io::CopyingOutputStreamAdaptor( outStream = new google::protobuf::io::CopyingOutputStreamAdaptor(
new PbQtOutputStream(clientSock)); new PbQtOutputStream(clientSock));
outStream->SetOwnsCopyingStream(true); outStream->SetOwnsCopyingStream(true);
connect(clientSock, SIGNAL(readyRead()), connect(clientSock, SIGNAL(readyRead()),
this, SLOT(when_dataAvail()), Qt::DirectConnection); this, SLOT(on_clientSock_dataAvail()));
connect(clientSock, SIGNAL(disconnected()), connect(clientSock, SIGNAL(disconnected()),
this, SLOT(when_disconnected())); this, SLOT(on_clientSock_disconnected()));
connect(clientSock, SIGNAL(error(QAbstractSocket::SocketError)), connect(clientSock, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(when_error(QAbstractSocket::SocketError))); this, SLOT(on_clientSock_error(QAbstractSocket::SocketError)));
exec();
} }
QString RpcThread::errorString() void RpcConnection::sendRpcReply(PbRpcController *controller)
{
return errorString_;
}
void RpcThread::done(PbRpcController *controller)
{ {
google::protobuf::Message *response = controller->response(); google::protobuf::Message *response = controller->response();
QIODevice *blob; QIODevice *blob;
@ -96,8 +96,6 @@ void RpcThread::done(PbRpcController *controller)
char* const msg = &msgBuf[0]; char* const msg = &msgBuf[0];
int len; int len;
//qDebug("In RpcThread::done");
if (controller->Failed()) if (controller->Failed())
{ {
qDebug("rpc failed"); qDebug("rpc failed");
@ -160,28 +158,23 @@ _exit:
isPending = false; isPending = false;
} }
void RpcThread::when_disconnected() void RpcConnection::on_clientSock_disconnected()
{ {
qDebug("connection closed from %s: %d", qDebug("connection closed from %s: %d",
clientSock->peerAddress().toString().toAscii().constData(), clientSock->peerAddress().toString().toAscii().constData(),
clientSock->peerPort()); clientSock->peerPort());
delete inStream; deleteLater();
delete outStream; emit closed();
clientSock->deleteLater();
clientSock = NULL;
quit();
} }
void RpcThread::when_error(QAbstractSocket::SocketError socketError) void RpcConnection::on_clientSock_error(QAbstractSocket::SocketError socketError)
{ {
qDebug("%s (%d)", clientSock->errorString().toAscii().constData(), qDebug("%s (%d)", clientSock->errorString().toAscii().constData(),
socketError); socketError);
} }
void RpcThread::when_dataAvail() void RpcConnection::on_clientSock_dataAvail()
{ {
uchar msg[PB_HDR_SIZE]; uchar msg[PB_HDR_SIZE];
int msgLen; int msgLen;
@ -256,7 +249,8 @@ void RpcThread::when_dataAvail()
//qDebug("before service->callmethod()"); //qDebug("before service->callmethod()");
service->CallMethod(methodDesc, controller, req, resp, service->CallMethod(methodDesc, controller, req, resp,
google::protobuf::NewCallback(this, &RpcThread::done, controller)); google::protobuf::NewCallback(this, &RpcConnection::sendRpcReply,
controller));
parsing = false; parsing = false;

View File

@ -17,10 +17,9 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/> along with this program. If not, see <http://www.gnu.org/licenses/>
*/ */
#ifndef _RPC_THREAD_H #ifndef _RPC_CONNECTION_H
#define _RPC_THREAD_H #define _RPC_CONNECTION_H
#include <QThread>
#include <QAbstractSocket> #include <QAbstractSocket>
// forward declarations // forward declarations
@ -36,25 +35,25 @@ namespace google {
} }
} }
class RpcThread : public QThread class RpcConnection : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
RpcThread(int socketDescriptor, RpcConnection(int socketDescriptor, ::google::protobuf::Service *service);
::google::protobuf::Service *service, virtual ~RpcConnection();
QObject *parent);
virtual ~RpcThread();
void run();
private: private:
QString errorString(); // FIXME: needed? why? void sendRpcReply(PbRpcController *controller);
void done(PbRpcController *controller);
signals:
void closed();
private slots: private slots:
void when_disconnected(); void start();
void when_dataAvail(); void on_clientSock_dataAvail();
void when_error(QAbstractSocket::SocketError socketError); void on_clientSock_error(QAbstractSocket::SocketError socketError);
void on_clientSock_disconnected();
private: private:
int socketDescriptor; int socketDescriptor;
@ -66,7 +65,6 @@ private:
bool isPending; bool isPending;
int pendingMethodId; int pendingMethodId;
QString errorString_;
}; };
#endif #endif

View File

@ -1,5 +1,5 @@
/* /*
Copyright (C) 2010 Srivats P. Copyright (C) 2010, 2014 Srivats P.
This file is part of "Ostinato" This file is part of "Ostinato"
@ -19,7 +19,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
#include "rpcserver.h" #include "rpcserver.h"
#include "rpcthread.h" #include "rpcconn.h"
#include <QThread>
// FIXME: QThreadX till we change minimum version of Qt from Qt4.3+ to Qt4.4+
class QThreadX: public QThread
{
protected:
virtual ~QThreadX() { qDebug("QThreadX going down!"); }
void run() { exec(); }
};
RpcServer::RpcServer() RpcServer::RpcServer()
{ {
@ -50,8 +60,19 @@ bool RpcServer::registerService(::google::protobuf::Service *service,
void RpcServer::incomingConnection(int socketDescriptor) void RpcServer::incomingConnection(int socketDescriptor)
{ {
RpcThread *thread = new RpcThread(socketDescriptor, service, this); QThread *thread = new QThreadX; // FIXME:QThreadX pending Qt4.4+
RpcConnection *conn = new RpcConnection(socketDescriptor, service);
conn->moveToThread(thread);
connect(thread, SIGNAL(started()), conn, SLOT(start()));
// NOTE: conn "self-destructs" after emitting closed
// use 'closed' to stop execution of the thread
connect(conn, SIGNAL(closed()), thread, SLOT(quit()));
// setup thread to "self-destruct" when it is done
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start(); thread->start();
} }

View File

@ -20,17 +20,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
#ifndef _RPC_SERVER_H #ifndef _RPC_SERVER_H
#define _RPC_SERVER_H #define _RPC_SERVER_H
#if 0
#include <google/protobuf/message.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <QTcpSocket>
#include "pbrpccommon.h"
#include "pbrpccontroller.h"
#endif
#include <QTcpServer> #include <QTcpServer>
// forward declaration // forward declaration
@ -44,18 +33,6 @@ class RpcServer : public QTcpServer
{ {
Q_OBJECT Q_OBJECT
#if 0
QTcpServer *server;
QTcpSocket *clientSock;
::google::protobuf::io::CopyingInputStreamAdaptor *inStream;
::google::protobuf::io::CopyingOutputStreamAdaptor *outStream;
bool isPending;
int pendingMethodId;
QString errorString_;
#endif
public: public:
RpcServer(); //! \todo (LOW) use 'parent' param RpcServer(); //! \todo (LOW) use 'parent' param
virtual ~RpcServer(); virtual ~RpcServer();
@ -66,16 +43,6 @@ public:
protected: protected:
void incomingConnection(int socketDescriptor); void incomingConnection(int socketDescriptor);
#if 0
QString errorString();
void done(PbRpcController *controller);
private slots:
void when_newConnection();
void when_disconnected();
void when_dataAvail();
void when_error(QAbstractSocket::SocketError socketError);
#endif
private: private:
::google::protobuf::Service *service; ::google::protobuf::Service *service;
}; };