深入浅出Alljoyn——实例分析之远程调用(Method)篇
深入浅出就是很深入的学习了很久,还是只学了毛皮,呵呵!
服务端完整代码:
#include <qcc/platform.h> #include <assert.h>
#include <signal.h>
#include <stdio.h>
#include <vector> #include <qcc/String.h> #include <alljoyn/BusAttachment.h>
#include <alljoyn/DBusStd.h>
#include <alljoyn/AllJoynStd.h>
#include <alljoyn/BusObject.h>
#include <alljoyn/MsgArg.h>
#include <alljoyn/version.h> #include <alljoyn/Status.h> using namespace std;
using namespace qcc;
using namespace ajn; /*constants*/
static const char* INTERFACE_NAME = "org.alljoyn.Bus.sample";
static const char* SERVICE_NAME = "org.alljoyn.Bus.sample";
static const char* SERVICE_PATH = "/sample";
static const SessionPort SERVICE_PORT = ; static volatile sig_atomic_t s_interrupt = false; static void SigIntHandler(int sig)
{
s_interrupt = true;
} class BasicSampleObject : public BusObject {
public:
BasicSampleObject(BusAttachment& bus, const char* path) :
BusObject(path)
{
/** Add the test interface to this object */
const InterfaceDescription* exampleIntf = bus.GetInterface(INTERFACE_NAME);
assert(exampleIntf);
AddInterface(*exampleIntf); /** Register the method handlers with the object */
const MethodEntry methodEntries[] = {
{ exampleIntf->GetMember("cat"), static_cast<MessageReceiver::MethodHandler>(&BasicSampleObject::Cat) }
};
QStatus status = AddMethodHandlers(methodEntries, sizeof(methodEntries) / sizeof(methodEntries[]));
if (ER_OK != status) {
printf("Failed to register method handlers for BasicSampleObject.\n");
}
} void ObjectRegistered()
{
BusObject::ObjectRegistered();
printf("ObjectRegistered has been called.\n");
} void Cat(const InterfaceDescription::Member* member, Message& msg)
{
/* Concatenate the two input strings and reply with the result. */
qcc::String inStr1 = msg->GetArg()->v_string.str;
qcc::String inStr2 = msg->GetArg()->v_string.str;
qcc::String outStr = inStr1 + inStr2; MsgArg outArg("s", outStr.c_str());
QStatus status = MethodReply(msg, &outArg, );
if (ER_OK != status) {
printf("Ping: Error sending reply.\n");
}
}
}; class MyBusListener : public BusListener, public SessionPortListener {
void NameOwnerChanged(const char* busName, const char* previousOwner, const char* newOwner)
{
if (newOwner && ( == strcmp(busName, SERVICE_NAME))) {
printf("NameOwnerChanged: name=%s, oldOwner=%s, newOwner=%s.\n",
busName,
previousOwner ? previousOwner : "<none>",
newOwner ? newOwner : "<none>");
}
}
bool AcceptSessionJoiner(SessionPort sessionPort, const char* joiner, const SessionOpts& opts)
{
if (sessionPort != SERVICE_PORT) {
printf("Rejecting join attempt on unexpected session port %d.\n", sessionPort);
return false;
}
printf("Accepting join session request from %s (opts.proximity=%x, opts.traffic=%x, opts.transports=%x).\n",
joiner, opts.proximity, opts.traffic, opts.transports);
return true;
}
}; /** The bus listener object. */
static MyBusListener s_busListener; /** Top level message bus object. */
static BusAttachment* s_msgBus = NULL; /** Create the interface, report the result to stdout, and return the result status. */
QStatus CreateInterface(void)
{
/* Add org.alljoyn.Bus.method_sample interface */
InterfaceDescription* testIntf = NULL;
QStatus status = s_msgBus->CreateInterface(INTERFACE_NAME, testIntf); if (status == ER_OK) {
printf("Interface created.\n");
testIntf->AddMethod("cat", "ss", "s", "inStr1,inStr2,outStr", );
testIntf->Activate();
} else {
printf("Failed to create interface '%s'.\n", INTERFACE_NAME);
} return status;
} /** Register the bus object and connect, report the result to stdout, and return the status code. */
QStatus RegisterBusObject(BasicSampleObject* obj)
{
QStatus status = s_msgBus->RegisterBusObject(*obj); if (ER_OK == status) {
printf("RegisterBusObject succeeded.\n");
} else {
printf("RegisterBusObject failed (%s).\n", QCC_StatusText(status));
} return status;
} /** Connect, report the result to stdout, and return the status code. */
QStatus ConnectBusAttachment(void)
{
QStatus status = s_msgBus->Connect(); if (ER_OK == status) {
printf("Connect to '%s' succeeded.\n", s_msgBus->GetConnectSpec().c_str());
} else {
printf("Failed to connect to '%s' (%s).\n", s_msgBus->GetConnectSpec().c_str(), QCC_StatusText(status));
} return status;
} /** Start the message bus, report the result to stdout, and return the status code. */
QStatus StartMessageBus(void)
{
QStatus status = s_msgBus->Start(); if (ER_OK == status) {
printf("BusAttachment started.\n");
} else {
printf("Start of BusAttachment failed (%s).\n", QCC_StatusText(status));
} return status;
} /** Create the session, report the result to stdout, and return the status code. */
QStatus CreateSession(TransportMask mask)
{
SessionOpts opts(SessionOpts::TRAFFIC_MESSAGES, false, SessionOpts::PROXIMITY_ANY, mask);
SessionPort sp = SERVICE_PORT;
QStatus status = s_msgBus->BindSessionPort(sp, opts, s_busListener); if (ER_OK == status) {
printf("BindSessionPort succeeded.\n");
} else {
printf("BindSessionPort failed (%s).\n", QCC_StatusText(status));
} return status;
} /** Advertise the service name, report the result to stdout, and return the status code. */
QStatus AdvertiseName(TransportMask mask)
{
QStatus status = s_msgBus->AdvertiseName(SERVICE_NAME, mask); if (ER_OK == status) {
printf("Advertisement of the service name '%s' succeeded.\n", SERVICE_NAME);
} else {
printf("Failed to advertise name '%s' (%s).\n", SERVICE_NAME, QCC_StatusText(status));
} return status;
} /** Request the service name, report the result to stdout, and return the status code. */
QStatus RequestName(void)
{
const uint32_t flags = DBUS_NAME_FLAG_REPLACE_EXISTING | DBUS_NAME_FLAG_DO_NOT_QUEUE;
QStatus status = s_msgBus->RequestName(SERVICE_NAME, flags); if (ER_OK == status) {
printf("RequestName('%s') succeeded.\n", SERVICE_NAME);
} else {
printf("RequestName('%s') failed (status=%s).\n", SERVICE_NAME, QCC_StatusText(status));
} return status;
} /** Wait for SIGINT before continuing. */
void WaitForSigInt(void)
{
while (s_interrupt == false) {
#ifdef _WIN32
Sleep();
#else
usleep( * );
#endif
}
} /** Main entry point */
int main(int argc, char** argv, char** envArg)
{
printf("AllJoyn Library version: %s.\n", ajn::GetVersion());
printf("AllJoyn Library build info: %s.\n", ajn::GetBuildInfo()); /* Install SIGINT handler */
signal(SIGINT, SigIntHandler); QStatus status = ER_OK; /* Create message bus */
s_msgBus = new BusAttachment("myApp", true); if (!s_msgBus) {
status = ER_OUT_OF_MEMORY;
} if (ER_OK == status) {
status = CreateInterface();
} if (ER_OK == status) {
s_msgBus->RegisterBusListener(s_busListener);
} if (ER_OK == status) {
status = StartMessageBus();
} BasicSampleObject testObj(*s_msgBus, SERVICE_PATH); if (ER_OK == status) {
status = RegisterBusObject(&testObj);
} if (ER_OK == status) {
status = ConnectBusAttachment();
} /*
* Advertise this service on the bus.
* There are three steps to advertising this service on the bus.
* 1) Request a well-known name that will be used by the client to discover
* this service.
* 2) Create a session.
* 3) Advertise the well-known name.
*/
if (ER_OK == status) {
status = RequestName();
} const TransportMask SERVICE_TRANSPORT_TYPE = TRANSPORT_ANY; if (ER_OK == status) {
status = CreateSession(SERVICE_TRANSPORT_TYPE);
} if (ER_OK == status) {
status = AdvertiseName(SERVICE_TRANSPORT_TYPE);
} /* Perform the service asynchronously until the user signals for an exit. */
if (ER_OK == status) {
WaitForSigInt();
} /* Clean up msg bus */
delete s_msgBus;
s_msgBus = NULL; printf("Basic service exiting with status 0x%04x (%s).\n", status, QCC_StatusText(status)); return (int) status;
}
服务端主流程解析:
int main(int argc, char** argv, char** envArg)
{
/* 注册系统信号回调函数*/
signal(SIGINT, SigIntHandler); /* 创建Bus连接器 */
s_msgBus = new BusAttachment("myApp", true); /* 创建object 的接口*/
status = CreateInterface(); /*绑定总线监听器*/
s_msgBus->RegisterBusListener(s_busListener); /*开启总线*/
status = StartMessageBus(); /*实例化对象*/
BasicSampleObject testObj(*s_msgBus, SERVICE_PATH); /*总线附件上注册对象*/
status = RegisterBusObject(&testObj); /*连接到总线上*/
status = ConnectToDaemon(); /*请求一个服务名即wellknow name*/
status = RequestName(); const TransportMask SERVICE_TRANSPORT_TYPE = TRANSPORT_ANY; /*创建一个会话*/
status = CreateSession(SERVICE_TRANSPORT_TYPE); /*在总线上广播服务名*/
status = AdvertiseName(SERVICE_TRANSPORT_TYPE); /* 等待用户终止 */
WaitForSigInt(); /* 释放资源 */
delete s_msgBus;
s_msgBus = NULL; return (int) status;
}
客户端完整代码:
#include <qcc/platform.h> #include <assert.h>
#include <signal.h>
#include <stdio.h>
#include <vector> #include <qcc/String.h> #include <alljoyn/BusAttachment.h>
#include <alljoyn/version.h>
#include <alljoyn/AllJoynStd.h>
#include <alljoyn/Status.h> using namespace std;
using namespace qcc;
using namespace ajn; /** Static top level message bus object */
static BusAttachment* g_msgBus = NULL; /*constants*/
static const char* INTERFACE_NAME = "org.alljoyn.Bus.sample";
static const char* SERVICE_NAME = "org.alljoyn.Bus.sample";
static const char* SERVICE_PATH = "/sample";
static const SessionPort SERVICE_PORT = ; static bool s_joinComplete = false;
static SessionId s_sessionId = ; static volatile sig_atomic_t s_interrupt = false; static void SigIntHandler(int sig)
{
s_interrupt = true;
} /** AllJoynListener receives discovery events from AllJoyn */
class MyBusListener : public BusListener, public SessionListener {
public:
void FoundAdvertisedName(const char* name, TransportMask transport, const char* namePrefix)
{
if ( == strcmp(name, SERVICE_NAME)) {
printf("FoundAdvertisedName(name='%s', prefix='%s')\n", name, namePrefix); /* We found a remote bus that is advertising basic service's well-known name so connect to it. */
/* Since we are in a callback we must enable concurrent callbacks before calling a synchronous method. */
g_msgBus->EnableConcurrentCallbacks();
SessionOpts opts(SessionOpts::TRAFFIC_MESSAGES, false, SessionOpts::PROXIMITY_ANY, TRANSPORT_ANY);
QStatus status = g_msgBus->JoinSession(name, SERVICE_PORT, this, s_sessionId, opts);
if (ER_OK == status) {
printf("JoinSession SUCCESS (Session id=%d).\n", s_sessionId);
} else {
printf("JoinSession failed (status=%s).\n", QCC_StatusText(status));
}
}
s_joinComplete = true;
} void NameOwnerChanged(const char* busName, const char* previousOwner, const char* newOwner)
{
if (newOwner && ( == strcmp(busName, SERVICE_NAME))) {
printf("NameOwnerChanged: name='%s', oldOwner='%s', newOwner='%s'.\n",
busName,
previousOwner ? previousOwner : "<none>",
newOwner ? newOwner : "<none>");
}
}
}; /** Create the interface, report the result to stdout, and return the result status. */
QStatus CreateInterface(void)
{
/* Add org.alljoyn.Bus.method_sample interface */
InterfaceDescription* testIntf = NULL;
QStatus status = g_msgBus->CreateInterface(INTERFACE_NAME, testIntf); if (status == ER_OK) {
printf("Interface '%s' created.\n", INTERFACE_NAME);
testIntf->AddMethod("cat", "ss", "s", "inStr1,inStr2,outStr", );
testIntf->Activate();
} else {
printf("Failed to create interface '%s'.\n", INTERFACE_NAME);
} return status;
} /** Start the message bus, report the result to stdout, and return the result status. */
QStatus StartMessageBus(void)
{
QStatus status = g_msgBus->Start(); if (ER_OK == status) {
printf("BusAttachment started.\n");
} else {
printf("BusAttachment::Start failed.\n");
} return status;
} /** Handle the connection to the bus, report the result to stdout, and return the result status. */
QStatus ConnectToBus(void)
{
QStatus status = g_msgBus->Connect(); if (ER_OK == status) {
printf("BusAttachment connected to '%s'.\n", g_msgBus->GetConnectSpec().c_str());
} else {
printf("BusAttachment::Connect('%s') failed.\n", g_msgBus->GetConnectSpec().c_str());
} return status;
} /** Register a bus listener in order to get discovery indications and report the event to stdout. */
void RegisterBusListener(void)
{
/* Static bus listener */
static MyBusListener s_busListener; g_msgBus->RegisterBusListener(s_busListener);
printf("BusListener Registered.\n");
} /** Begin discovery on the well-known name of the service to be called, report the result to
stdout, and return the result status. */
QStatus FindAdvertisedName(void)
{
/* Begin discovery on the well-known name of the service to be called */
QStatus status = g_msgBus->FindAdvertisedName(SERVICE_NAME); if (status == ER_OK) {
printf("org.alljoyn.Bus.FindAdvertisedName ('%s') succeeded.\n", SERVICE_NAME);
} else {
printf("org.alljoyn.Bus.FindAdvertisedName ('%s') failed (%s).\n", SERVICE_NAME, QCC_StatusText(status));
} return status;
} /** Wait for join session to complete, report the event to stdout, and return the result status. */
QStatus WaitForJoinSessionCompletion(void)
{
unsigned int count = ; while (!s_joinComplete && !s_interrupt) {
if ( == (count++ % )) {
printf("Waited %u seconds for JoinSession completion.\n", count / );
} #ifdef _WIN32
Sleep();
#else
usleep( * );
#endif
} return s_joinComplete && !s_interrupt ? ER_OK : ER_ALLJOYN_JOINSESSION_REPLY_CONNECT_FAILED;
} /** Do a method call, report the result to stdout, and return the result status. */
QStatus MakeMethodCall(void)
{
ProxyBusObject remoteObj(*g_msgBus, SERVICE_NAME, SERVICE_PATH, s_sessionId);
const InterfaceDescription* alljoynTestIntf = g_msgBus->GetInterface(INTERFACE_NAME); assert(alljoynTestIntf);
remoteObj.AddInterface(*alljoynTestIntf); Message reply(*g_msgBus);
MsgArg inputs[]; inputs[].Set("s", "Hello ");
inputs[].Set("s", "World!"); QStatus status = remoteObj.MethodCall(SERVICE_NAME, "cat", inputs, , reply, ); if (ER_OK == status) {
printf("'%s.%s' (path='%s') returned '%s'.\n", SERVICE_NAME, "cat",
SERVICE_PATH, reply->GetArg()->v_string.str);
} else {
printf("MethodCall on '%s.%s' failed.", SERVICE_NAME, "cat");
} return status;
} /** Main entry point */
int main(int argc, char** argv, char** envArg)
{
printf("AllJoyn Library version: %s.\n", ajn::GetVersion());
printf("AllJoyn Library build info: %s.\n", ajn::GetBuildInfo()); /* Install SIGINT handler. */
signal(SIGINT, SigIntHandler); QStatus status = ER_OK; /* Create message bus. */
g_msgBus = new BusAttachment("myApp", true); /* This test for NULL is only required if new() behavior is to return NULL
* instead of throwing an exception upon an out of memory failure.
*/
if (!g_msgBus) {
status = ER_OUT_OF_MEMORY;
} if (ER_OK == status) {
status = CreateInterface();
} if (ER_OK == status) {
status = StartMessageBus();
} if (ER_OK == status) {
status = ConnectToBus();
} if (ER_OK == status) {
RegisterBusListener();
status = FindAdvertisedName();
} if (ER_OK == status) {
status = WaitForJoinSessionCompletion();
} if (ER_OK == status) {
status = MakeMethodCall();
} /* Deallocate bus */
delete g_msgBus;
g_msgBus = NULL; printf("Basic client exiting with status 0x%04x (%s).\n", status, QCC_StatusText(status)); return (int) status;
}
客户端主流程解析:
int main(int argc, char** argv, char** envArg)
{
printf("AllJoyn Library version: %s.\n", ajn::GetVersion());
printf("AllJoyn Library build info: %s.\n", ajn::GetBuildInfo()); /* 注册系统信号回调函数*/
signal(SIGINT, SigIntHandler); QStatus status = ER_OK; /* 创建Bus连接器 */
g_msgBus = new BusAttachment("myApp", true); /* This test for NULL is only required if new() behavior is to return NULL
* instead of throwing an exception upon an out of memory failure.
*/
if (!g_msgBus) {
status = ER_OUT_OF_MEMORY;
}
/* 创建object 的接口*/
if (ER_OK == status) {
status = CreateInterface();
}
/*开启总线*/
if (ER_OK == status) {
status = StartMessageBus();
}
/*连接到总线上*/ if (ER_OK == status) {
status = ConnectToBus();
} if (ER_OK == status) {
RegisterBusListener();/*绑定总线监听器*/
status = FindAdvertisedName();/*在总线上发现服务名*/
} if (ER_OK == status) {
status = WaitForJoinSessionCompletion();
} /*远程调用方法*/ if (ER_OK == status) {
status = MakeMethodCall();
} /* 释放资源 */
delete g_msgBus;
g_msgBus = NULL; printf("Basic client exiting with status 0x%04x (%s).\n", status, QCC_StatusText(status)); return (int) status;
}
通信过程中比较重要的几点:
1、 接口由bus连接器创建和保存所以创建的实例
2、 对象具体实现接口的属性(方法,属性和信号),与具体接口绑定,作为对象对外的接口。(可以含有多个接口)
3、连接总线s_msgBus->Connect()是通过dbus方式实现的,利用了dbus中现存的方法和消息。
用下面的图可能表达的更清楚:
通过Bus建立好连接后,服务端的object提供接口比如说方法, 那么客户端的object只需产生一个object的代理,即可调用服务端的object提供接口,是不是比较好玩。
服务端方法调用的代码:
服务端:通过接受客户端提供的参数,并通过MethodReply()给客户端返回结果
void Cat(const InterfaceDescription::Member* member, Message& msg)
{
/* Concatenate the two input strings and reply with the result. */
qcc::String inStr1 = msg->GetArg()->v_string.str;
qcc::String inStr2 = msg->GetArg()->v_string.str;
qcc::String outStr = inStr1 + inStr2; MsgArg outArg("s", outStr.c_str());
QStatus status = MethodReply(msg, &outArg, );
if (ER_OK != status) {
printf("Ping: Error sending reply.\n");
}
}
客户端方法调用的代码:
QStatus status = remoteObj.MethodCall(SERVICE_NAME, "cat", inputs, , reply, );
说了这么多,这个代码的作用是干嘛呢,就是服务端提供一个连接字符串(str1+str2)的方法,并将结果返回给客户端。当然这只是一个很简单sample,如果你将你家电视定义了换台方法的话,用手机就可以通过调用这个方法进行控制了,当然前提是你的电视和手机在一个网内!
一个人学习有时挺没意思的,那就加入q群49073007一起交流讨论吧。
深入浅出Alljoyn——实例分析之远程调用(Method)篇的更多相关文章
- Openstack Nova 源码分析 — RPC 远程调用过程
目录 目录 Nova Project Services Project 的程序入口 setuppy Nova中RPC远程过程调用 nova-compute RPC API的实现 novacompute ...
- Delphi实例分析:远程传输数据和文件
在Windows操作系统的平台上,WinSock是首选的网络编程接口,用于在网络上传输数据和交换信息,它构成了Windows操作系统进行网络编程的基础.对于编写网络应用程序来说,WinSock是一门非 ...
- 《Spring技术内幕》学习笔记17——Spring HTTP调用器实现远程调用
1.Spring中,HTTPInvoker(HTTP调用器)是通过基于HTTP协议的分布式远程调用解决方案,和java RMI一样,HTTP调用器也需要使用java的对象序列化机制完成客户端和服务器端 ...
- 【spring源码学习】spring的远程调用实现源码分析
[一]spring的远程调用提供的基础类 (1)org.springframework.remoting.support.RemotingSupport ===>spring提供实现的远程调用客 ...
- Android 学习笔记之WebService实现远程调用+内部原理分析...
PS:终于可以抽出时间写写博客了,忙着学校的三周破实训外加替考...三周了,没怎么学习...哎... 学习内容: 1.WebService 实现远程方法的调用 什么是WebService... ...
- RPC原理及RPC实例分析
在学校期间大家都写过不少程序,比如写个hello world服务类,然后本地调用下,如下所示.这些程序的特点是服务消费方和服务提供方是本地调用关系. 1 2 3 4 5 6 public class ...
- RPC-原理及RPC实例分析
还有就是:RPC支持的BIO,NIO的理解 (1)BIO: Blocking IO;同步阻塞: (2)NIO:Non-Blocking IO, 同步非阻塞; 参考:IO多路复用,同步,异步,阻塞和非阻 ...
- Dubbo源码学习总结系列二 dubbo-rpc远程调用模块
dubbo本质是一个RPC框架,我们首先讨论这个骨干中的骨干,dubbo-rpc模块. 主要讨论一下几部分内容: 一.此模块在dubbo整体框架中的作用: 二.此模块需要完成的需求功能点及接口定义: ...
- RPC原理及RPC实例分析(转)
出处:https://my.oschina.net/hosee/blog/711632 在学校期间大家都写过不少程序,比如写个hello world服务类,然后本地调用下,如下所示.这些程序的特点是服 ...
随机推荐
- 第二十二篇:在SOUI中使用代码向窗口中插入子窗口
使用SOUI开发客户端UI程序,通常也推荐使用XML代码来创建窗口,这样创建的窗口使用方便,当窗口大小改变时,内部的子窗口也更容易协同变化. 但是最近不断有网友咨询如何使用代码来创建SOUI子窗口,特 ...
- fullPage.js学习笔记
中秋节,一个人呆着,挺无聊的,还是学习最有趣,不论是什么,开阔视野都是好的. 参考网址:http://www.dowebok.com/77.html 上面有详细介绍及案例展示,很不错哦,可以先去看看 ...
- Nginx - Windows下作为服务启动
Nginx官方没有提供作为服务启动nginx的方案.以服务启动nginx依赖于winsw,当前最新版是1.19. 参考:https://segmentfault.com/a/1190000006807 ...
- 《UML大战需求分析》阅读随笔(六)
在我们做的代码设计中分为系统设计和程序设计.程序设计是系统设计中模拟程序的执行逻辑,定义客户机服务器对象合作的框架的那个部分.程序和事务设计中,作者讲述到程序和事务设计将系统设计制品放在一起,并作为系 ...
- python 爬虫(五)
下载媒体文件 I 使用urllib.request.urlretrieve方法可以下载文件存为指定文件 from urllib.request import urlretrieve from urll ...
- 获取终端ip地址
网上找的,记录下 import java.io.*; import java.net.*; import java.util.*; //import org.apache.http.conn.util ...
- Code Complete 笔记—— 第二章 用隐喻来更充分理解软件开发
在这章里面,提到的隐喻,类同于比喻(建模)的方法的去理解软件开发. 隐喻的优点在于其可预期的效果能被所有人所理解.不必要的沟通和误解也因此大为减低,学习与教授更为快速,实际上,隐喻是对概念进行内在化和 ...
- linux菜鸟日记(4)
使用一个简单的for循环和if判断语句实现某个网段内所有ping所有客户机的shell程序: ..} do >&; then echo " ${i}通" else e ...
- Day 1:开始重新学习
离开很久,前几天翻出以前做过的程序居然还能正常运行.有一点后悔,为什么当初没有坚持做下去.Delphi园地前一阵也曾经宣布要关站,但仍然坚持过来了,在此向站长致敬!我也要重新开始! 附图:Delphi ...
- Hybrid App经验解读 一
郑昀编纂 关键词:Hybrid,Zepto,Fastclick,Backbone,sui,SPA,pushState,跨域,CORS click 事件还是 tap 事件? Zepto 的 show/h ...