【AllJoyn框架-03】官方示例程序basic简单剖析

简介: 不论是自己编译源码还是从官方下载SDK,在alljoyn_core\samples下的代码很值得研究,有利于熟悉alljoyn框架的各种概念和编程套路。今天我且对basic程序作下简单剖析。 分服务端和客户端。首先看服务端:(我对示例代码做了精简,只保留最核心的API,这样更能抓住主要矛盾又不影响分析) int main(int argc, char** argv, char*

不论是自己编译源码还是从官方下载SDK,在alljoyn_core\samples下的代码很值得研究,有利于熟悉alljoyn框架的各种概念和编程套路。今天我且对basic程序作下简单剖析。


分服务端和客户端。首先看服务端:(我对示例代码做了精简,只保留最核心的API,这样更能抓住主要矛盾又不影响分析)

int main(int argc, char** argv, char** envArg)
{
    signal(SIGINT, SigIntHandler);//创建信号处理,类似于Linux中做法
	
	/*
		很多函数调用都返回了这种类型的值,与ER_OK进行比较
		我在这里就做了精简,但具体写时是需要进行异常检测的
	*/
    QStatus status = ER_OK;
	
	/*
		创建BusAttachment对象,myApp为应用程序名,且允许从远程设备接收消息
	*/
    s_msgBus = new BusAttachment("myApp", true);
	
	/*
		为总线创建接口,以INTERFACE_NAME为接口名,testIntf存储接口描述信息
	*/
	InterfaceDescription* testIntf = NULL;
    s_msgBus->CreateInterface(INTERFACE_NAME, testIntf);
	
	/*
		为接口添加方法,cat为方法名,后面为输入、输出参数及列表
	*/
    testIntf->AddMethod("cat", "ss",  "s", "inStr1,inStr2,outStr", 0);
	
	/*
		接口在使用之前要先激活,激活之后不能再被修改
	*/
    testIntf->Activate();
	
	/*
		注册总线监听对象,用以监听总线上的事件通知
		s_busListener是一个子对象,继承自BusListener,SessionPortListener
		重新实现了NameOwnerChanged,AcceptSessionJoiner等虚函数
	*/
    s_msgBus->RegisterBusListener(s_busListener);
	
	/*
		启动BusAttachment对象中独立的线程,准备运行
		它仅仅是启动总线,发送和接收消息要在Connect之后才能开始
		BusAttachment线程模型中有一个线程很特殊,它会给注册的监听对象发送callback(回调)
		像BusAttachment的Start,Stop,Join方法都可看成是对底层线程方法的映射或叫封装
	*/
    s_msgBus->Start();
	
	/*
		BasicSampleObject是继承BusObject的子类,它里面实现了方法处理函数Cat
	*/
    BasicSampleObject testObj;
	//为对象添加接口
	testObj.AddInterface(*testIntf);
	
	//MethodEntry是个结构体
	const MethodEntry methodEntries[] = {
            { exampleIntf->GetMember("cat"), static_cast<MessageReceiver::MethodHandler>(&BasicSampleObject::Cat) }
        };
	//添加方法处理函数,即Cat
    testObj.AddMethodHandlers(methodEntries, sizeof(methodEntries) / sizeof(methodEntries[0]));
	
	// 为总线注册总线对象
    s_msgBus->RegisterBusObject(testObj);
	
	/*
		开始连接到alljoyn router,有一个给定的目的地。如果Connect调用没有给参数,则试图使用一个
		bundled router,如果存在的话
		可以接收和发送消息了
	*/
    s_msbBus->Connect();
	
	/*
		开始发布服务,分三步:
		1、请求well-known name
		2、创建会话
		3、发布服务名
	*/
    const uint32_t flags = DBUS_NAME_FLAG_REPLACE_EXISTING | DBUS_NAME_FLAG_DO_NOT_QUEUE;
    s_msgBus->RequestName(SERVICE_NAME, flags);
	
    const TransportMask SERVICE_TRANSPORT_TYPE = TRANSPORT_ANY;
    SessionOpts opts(SessionOpts::TRAFFIC_MESSAGES, false, SessionOpts::PROXIMITY_ANY, SERVICE_TRANSPORT_TYPE);
    SessionPort sp = SERVICE_PORT;
	// 绑定会话端口
    QStatus status = s_msgBus->BindSessionPort(sp, opts, s_busListener);
	
    s_msgBus->AdvertiseName(SERVICE_NAME, mask);
	
	//等待信号,如果有中断则退出
    WaitForSigInt();
	
    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);
    QStatus status = ER_OK;
    g_msgBus = new BusAttachment("myApp", true);
    g_msgBus->CreateInterface(INTERFACE_NAME, testIntf);
	testIntf->AddMethod("cat", "ss",  "s", "inStr1,inStr2,outStr", 0);
	testIntf->Activate();
	
    g_msgBus->Start();
	g_msgBus->Connect();
    static MyBusListener s_busListener;
    g_msgBus->RegisterBusListener(s_busListener);
	//前面的代码与service一端差不多
	
	//寻找发布的服务
    g_msgBus->FindAdvertisedName(SERVICE_NAME);
	//等待接入会话
    WaitForJoinSessionCompletion();
	
	//创建代理对象进行远程调用
    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[2];

    inputs[0].Set("s", "Hello ");
    inputs[1].Set("s", "World!");
	
	//执行远程调用,reply返回结果
    QStatus status = remoteObj.MethodCall(SERVICE_NAME, "cat", inputs, 2, reply, 5000);
	
	//输出返回结果
    if (ER_OK == status) {
        printf("'%s.%s' (path='%s') returned '%s'.\n", SERVICE_NAME, "cat",
               SERVICE_PATH, reply->GetArg(0)->v_string.str);
 
    delete g_msgBus;
    g_msgBus = NULL;

    printf("Basic client exiting with status 0x%04x (%s).\n", status, QCC_StatusText(status));

    return (int) status;
}

有一现象得说明一下:当我把MakeMethodCall方法里的代码放进main中时,程序在最后析构的时候会发生异常,不过最后返回值还是会打印出来。若直接调用MakeMethodCall时就正常。


运行结果截图

服务端:


客户端:




由上可知向服务端发送了Hello World,执行了方法调用后返回合成后的字符串。

最后也顺便说一下另外几个工程,其实大致结构与上差不多,具体任务稍有差异

nameChanged_client是修改某个属性名,以signal_service为服务;

signalConsumer_client是订阅了某个属性名信号,一旦名称改变,它会有所反应,也以signal_servie为服务,若要看到现象,nameChanged_client也要参与进来。可参照下图


目录
相关文章
|
SQL 存储 数据库
实验4:SQL视图操作技巧与方法
在数据库管理系统中,视图(View)是一种虚拟表,它基于SQL查询的结果集创建,并不实际存储数据
|
机器学习/深度学习 资源调度 分布式计算
一切模型皆可联邦化:高斯朴素贝叶斯代码示例
一般情况下我们对联邦学习的理解都是大模型和深度学习模型才可以进行联邦学习,其实基本上只要包含参数的机器学习方法都可以使用联邦学习的方法保证数据隐私
164 4
|
Kubernetes 监控 API
【K8S系列】深入解析 ReplicaSet
【K8S系列】深入解析 ReplicaSet
741 1
|
SQL 弹性计算 Cloud Native
分布式事务 GTS 的价值和原理浅析
GTS 今年双 11 的成绩 今年 2684 亿的背后,有一个默默支撑,低调到几乎被遗忘的中间件云产品——GTS(全局事务服务,Global Transaction Service),稳稳地通过了自 2014 年诞生以来的第 5 次“大考”。
4563 81
分布式事务 GTS 的价值和原理浅析
|
JavaScript vr&ar 开发者
ejs模板引擎使用(独立使用,没有集成 express |学习笔记
快速学习ejs模板引擎使用(独立使用,没有集成 express)
ejs模板引擎使用(独立使用,没有集成 express |学习笔记
|
存储 Java Apache
Apache ZooKeeper - ZK的内存数据 + 持久化事务日志 + 数据快照 初探
Apache ZooKeeper - ZK的内存数据 + 持久化事务日志 + 数据快照 初探
479 0
|
3天前
|
云安全 人工智能 安全
AI被攻击怎么办?
阿里云提供 AI 全栈安全能力,其中对网络攻击的主动识别、智能阻断与快速响应构成其核心防线,依托原生安全防护为客户筑牢免疫屏障。
|
13天前
|
域名解析 人工智能
【实操攻略】手把手教学,免费领取.CN域名
即日起至2025年12月31日,购买万小智AI建站或云·企业官网,每单可免费领1个.CN域名首年!跟我了解领取攻略吧~