qtrpc2 - - qt developer days 2014 - home | qt …...2 about me • co-founded resara llc (2004-2012)...

40
www.ics.com QtRpc2 A Qt Based RPC Library By: Brendan Powers

Upload: others

Post on 20-Jul-2020

5 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

1

www.ics.com

QtRpc2

A Qt Based RPC LibraryBy: Brendan Powers

Page 2: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

2

www.ics.com

About Me

• Co-Founded Resara LLC (2004-2012)

• Linux infrastructure products

• Heavy use of Qt

• Used Qt’s core classes for back end code.

• Highly distributed applications

• Qt Software Engineer at ICS (2012-Present)

Page 3: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

3

www.ics.com

About Integrated Computer Solutions

• ICS is the largest Qt professional services firm in North America.

• ICS provides embedded, mobile, and desktop consulting services for Qt, multi-touch applications and GUI application development.

• As a Qt-Certified Training Partner, ICS has trained thousands of Qt developers.

• Visit www.ics.com for more info and free training videos.

Page 4: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

4

www.ics.com

The Problem

• Many applications spread among many servers

• Applications needed access to many different services

• Existing C++ RPC libraries were complicated and verbose

• A need for a flexible RPC framework, without increasing code complexity

Page 5: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

5

www.ics.com

The Solution – QtRpc2

• Ease of use is the first priority

• Uses Qt’s meta object system to simplify RPC calls

• Write services like you would create any QObject

• Remote functions act like normal C++ functions

• Wait, what about QtRpc 1?

• Used service files to generate templates

• Error handling was awkward

• Custom data types were difficult to implement

Page 6: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

6

www.ics.com

Features

• Simple to use

• Events and asynchronous function calls

• Simple error checking

• Token based authentication model

• Multiple transport modes (TCP, SSL, Named Pipe)

• Flexible threading model

• Service discovery

Page 7: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

7

www.ics.com

Where to get Qtrpc2

• Git repositoryhttps://github.com/brendan0powers/QtRpc2

• Ubuntu packages (Ubuntu 12.04 and up)apt-get install libqtrpc2-dev

• Windows binarieshttps://github.com/brendan0powers/QtRpc2/downloads

Page 8: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

8

www.ics.com

Architecture - Services

ProxyBase

ClientProxy ServiceProxy

Page 9: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

9

www.ics.com

Architecture – Server

Server ServiceProxy

Tcp Listener

ServiceProxy

ServiceProxy

Socket Listener

registerService()

Tcp Listener

Socket Listener

Tcp Listener

Socket Listener

Page 10: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

10

www.ics.com

Architecture – Client

ClientProxy

Page 11: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

11

www.ics.com

Basic Example - Server

class BasicService : public ServiceProxy {

Q_OBJECT

public:

explicit BasicService(QObject *parent = 0) {}

virtual ReturnValue auth(QString user, QString pass) {

return(true);

}

public slots:

ReturnValue addNumbers(int a, int b) {

return(a + b);

}

};

Page 12: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

12

www.ics.com

Basic Example - Server

int main(int argc, char *argv[]) {

QApplication app(argc,argv);

Server srv;

ServerProtocolListenerTcp tcp(&srv);

if(!tcp.listen(QHostAddress::Any, 10123)) {

qCritical() << "Failed to listen on port 10123!";

return(1);

}

srv.registerService<BasicService>("MyService");

return app.exec();

}

Page 13: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

13

www.ics.com

Basic Example - Client

class BasicService : public ClientProxy {

Q_OBJECT

QTRPC_CLIENTPROXY(BasicService)

public:

explicit BasicService(QObject *parent = 0) {}

signals:

ReturnValue addNumbers(int a, int b);

};

Page 14: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

14

www.ics.com

Basic Example - Clientint main(int argc, char *argv[]) {

QApplication app(argc,argv);

BasicService service;

ReturnValue ret = service.connect("tcp://localhost:10123/MyService");

if(ret.isError()) {

qCritical() << "Failed to connect:" << ret;

return(1);

}

ret = service.addNumbers(3,5);

if(ret.isError()) {

qCritical() << "Failed to call addNumbers():" << ret;

return(1);

}

}

Page 15: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

15

www.ics.com

ReturnValue

• Almost always used as the return type in QtRpc2 functions

• Inherits from QVariant

• Used for error checking

• Errors stored as an error number, and error message

• Important functions

• isError()

• errNumber()

• errString()

Page 16: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

16

www.ics.com

ReturnValue

• ReturnValue(5);

• ReturnValue(“Some Text”);

• ReturnValue(123, “This is an error!”);

• ReturnValue = QVariant::fromValue(CustomType);

• ReturnValue.value<CustomType>();

Page 17: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

17

www.ics.com

Events

• Behave exactly like Qt’s signals

• Can be connected to other signals, or slots

• Signified by the Event return type.

class TimeService : public ClientProxy {

Q_OBJECT

QTRPC_CLIENTPROXY(TimeService)

public:

explicit TimeService(QObject *parent = 0);

signals:

Event currentTime(QDateTime time);

};

Page 18: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

18

www.ics.com

Events - Client

QObject::connect(&service, SIGNAL(currentTime(QDateTime)), &object, SLOT(currentTime(QDateTime)));

void TimeObject::currentTime(QDateTime time) {

qDebug() << "Current Time:" << time.toString();

}

Page 19: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

19

www.ics.com

Events - Server

class TimeService : public ServiceProxy {

Q_OBJECT

public:

explicit TimeService(QObject *parent = 0);

virtual ReturnValue auth(QString user, QString pass);

public slots:

void timeout();

signals:

Event currentTime(QDateTime time);

private:

QTimer *m_timer;

};

Page 20: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

20

www.ics.com

Events - Server

TimeService::TimeService(QObject *parent) : ServiceProxy(parent) {

m_timer = new QTimer(this);

connect(m_timer, SIGNAL(timeout()), this, SLOT(timeout()));

}

ReturnValue TimeService::auth(QString user, QString pass) {

m_timer->start(1000);

return(true);

}

void TimeService::timeout() {

emit(currentTime(QDateTime::currentDateTime()));

}

Page 21: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

21

www.ics.com

Asynchronous Function Calls

• Normal function calls block until the server returns

• Asynchronous function calls call a slot when the server returns

• Add “QObject *, const char *” to any ClientProxy function to make is async

• the slot signature is (uint id, ReturnValue ret)

ReturnValue pause();ReturnValue pause(QObject *object, const char *slot);

ret = service.pause(&object, SLOT(pause(uint,ReturnValue)));

void TestObject::pause(uint id, ReturnValue ret) {if(ret.isError())

qDebug() << "Async Pause returned with an error:" << ret; else

qDebug() << "Async Pause returned.";}

Page 22: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

22

www.ics.com

Authentication

• Simple User/Password based authentication

• auth(Qstring user, QString pass)

• Return true, or any other value for success

• Return an error for failure

• Authentication token based authentication

• auth(AuthToken token)

• Supports more data than just username and password

• Can store server side data about the users session and authentication state

• Use the authToken() function in a service to get the current users token

Page 23: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

23

www.ics.com

Authentication - AuthToken

• Stores data in key/value pairs

• Client and Server data

• Client Data

• Data provided by the client for authentication

• Can be modified by the client

• Do not store session information in the client data

• Server Data

• Stores session information

• Cannot be modified by the client

Page 24: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

24

www.ics.com

Authentication - Server

ReturnValue BasicService::auth(QString user, QString pass) {

if((user == "joe") && (pass == "secret"))

return(true);

else

return(ReturnValue(1,"Incorrect username or password."));

}

Page 25: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

25

www.ics.com

Authentication - Client

ret = service.connect("tcp://jon:secret@localhost:10123/MyService");

if(ret.isError()) {

qCritical() << "Failed to connect:" << ret; return(1);

}

Page 26: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

26

www.ics.com

Transports

• QtRpc2 comes with several transports.

• TCP – tcp://

• ServerProtocolListenerTcp

• Basic transport for network communications

• SSL – tcps://

• ServerProtocolListenerTcp

• Encrypted TCP transport.

• You must set a valid private certificate on the server before use

Page 27: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

27

www.ics.com

Transports

• Socket – socket://

• ServerProtocolListenerSocket

• Uses sockets on UNIX systems, named pipes on Windows systems

• On Linux, you can get the UID and GID of the connecting user

Page 28: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

28

www.ics.com

SSL Example - Server

Server srv;

ServerProtocolListenerTcp tcp(&srv);

tcp.setSslMode(ServerProtocolListenerTcp::SslForced);

tcp.setCertificate("./examplecert.pem");

if(!tcp.listen(QHostAddress::Any, 10123)) {

qCritical() << "Failed to listen on port 10123!";

return(1);

}

srv.registerService<BasicService>("MyService");

Page 29: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

29

www.ics.com

SSL Example - Client

BasicService service;

ReturnValue ret = service.connect("tcps://localhost:10123/MyService");

if(ret.isError()) {

qCritical() << "Failed to connect:" << ret;

return(1);

}

Page 30: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

30

www.ics.com

Threading• QtRpc2 supports multiple threading modes

• Single Threaded

• All services are created in the main thread

• One service can block all others

Server srv(NULL, Server::SingleThread);

• Thread Per Instance

• A new thread is created for each service instance

• Services to not block each other

Server srv(NULL, Server::ThreadPerInstance);

Page 31: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

31

www.ics.com

Threading• Thread Pool

• Services are assigned to one thread in a thread pool

• Services can block other services using the same thread in the pool

• The default constructor uses thread pool mode, where the number of threads matches the number of cores

• You can specify the number of threads in the pool

//Thread pool mode. Threads = number of cores.Server srv;

//Thread pool mode. Threads = 3 Server srv(NULL, Server::ThreadPool, 3);

Page 32: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

32

www.ics.com

Threading – Client Side• All networking happens in a separate message bus thread

• Asynchronous function calls are not blocked by network delays

• ClientProxy object may only be used by one thread at a time

• If needed, a ClientProxy can be copied and used in 2 threads simultaneously

BasicService service; //Use in thread 1

ReturnValue ret = service.connect("tcp://localhost:10123/MyService");

if(ret.isError()) {

qCritical() << "Failed to connect:" <<

ret; return(1);

}

BasicService service2(service); //Use in thread 2

Page 33: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

33

www.ics.com

Custom Data Types

• Register your data type with the Qt meta-object system

• Create QDataStream operators

• Use QVariant::fromValue() and ReturnValue.value() to pack and unpack your data type

struct CustomData {int x; int y; int z;

};QDataStream& operator<<(QDataStream& d, const DataService::CustomData& object); QDataStream& operator>>(QDataStream& d, DataService::CustomData& object);Q_DECLARE_METATYPE(DataService::CustomData)

Page 34: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

34

www.ics.com

Custom Data Types

QTRPC_REGISTER_METATYPE(DataService::CustomData)

QDataStream& operator<<(QDataStream& d, const DataService::CustomData& object) {

d << object.x;

d << object.y;

d << object.z;

return(d);

}

QDataStream& operator>>(QDataStream& d, DataService::CustomData& object) {

d >> object.x;

d >> object.y;

d >> object.z;

return(d);

Page 35: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

35

www.ics.com

Returning Services From Functions

• Service can be returned from functions

• QtRpc2 takes ownership of the service object

• Service objects can be returned to more than one client at a time

ReturnValue DataService::getBasicService() {

return(new BasicService());

}

ReturnValue ret = service.getBasicService();

BasicService basic = ret;ret = basic.addNumbers(3,5);

Page 36: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

36

www.ics.com

Service Discovery

• Allows clients to find servers on the network without knowing their address ahead of time

• Uses the MDNS or App’s Bonjour protocol.

• Platform Requirements

• Windows – Bonjour SDK and Bonjour Printing Runtime.

• Linux – Avahi with MDNS compat libs

• Mac – Bonjour libraries provided by the Apple SDK

Page 37: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

37

www.ics.com

Service Discovery - Server

ServiceProxy *service = srv.registerService<BasicService>("MyService");

ServicePublisher pub(service);

pub.setPort(10123);

pub.publish();

Page 38: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

38

www.ics.com

Service Discovery - Client

TestObject::TestObject(QObject *parent) : QObject(parent) {

ServiceFinder *finder = new ServiceFinder("MyService",this);

QObject::connect(finder, SIGNAL(serviceEvent(ServiceFinder::Service)), this, SLOT(serviceEvent(ServiceFinder::Service)));

finder->scan(); }

void TestObject::serviceEvent(ServiceFinder::Service service) {

if(service.port() == 0)

return;

QString host = service.address().toString();

int port = service.port();

QString url = QString("tcp://%1:%2/MyService").arg(host).arg(port);

Page 39: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

39

www.ics.com

Room For Improvement

• Better documentation

• Templated ReturnValue class

• Non binary protocol option

• Packages for other Linux distributions

Page 40: QtRpc2 - - Qt Developer Days 2014 - Home | Qt …...2 About Me • Co-Founded Resara LLC (2004-2012) • Linux infrastructure products • Heavy use of Qt • Used Qt’s core classes

40

www.ics.com

Questions?