首页 > 代码库 > 深入浅出Alljoyn——实例分析之远程调用(Method)篇
深入浅出Alljoyn——实例分析之远程调用(Method)篇
深入浅出就是很深入的学习了很久,还是只学了毛皮,呵呵!
服务端完整代码:
1 #include <qcc/platform.h> 2 3 #include <assert.h> 4 #include <signal.h> 5 #include <stdio.h> 6 #include <vector> 7 8 #include <qcc/String.h> 9 10 #include <alljoyn/BusAttachment.h> 11 #include <alljoyn/DBusStd.h> 12 #include <alljoyn/AllJoynStd.h> 13 #include <alljoyn/BusObject.h> 14 #include <alljoyn/MsgArg.h> 15 #include <alljoyn/version.h> 16 17 #include <alljoyn/Status.h> 18 19 using namespace std; 20 using namespace qcc; 21 using namespace ajn; 22 23 /*constants*/ 24 static const char* INTERFACE_NAME = "org.alljoyn.Bus.sample"; 25 static const char* SERVICE_NAME = "org.alljoyn.Bus.sample"; 26 static const char* SERVICE_PATH = "/sample"; 27 static const SessionPort SERVICE_PORT = 25; 28 29 static volatile sig_atomic_t s_interrupt = false; 30 31 static void SigIntHandler(int sig) 32 { 33 s_interrupt = true; 34 } 35 36 class BasicSampleObject : public BusObject { 37 public: 38 BasicSampleObject(BusAttachment& bus, const char* path) : 39 BusObject(path) 40 { 41 /** Add the test interface to this object */ 42 const InterfaceDescription* exampleIntf = bus.GetInterface(INTERFACE_NAME); 43 assert(exampleIntf); 44 AddInterface(*exampleIntf); 45 46 /** Register the method handlers with the object */ 47 const MethodEntry methodEntries[] = { 48 { exampleIntf->GetMember("cat"), static_cast<MessageReceiver::MethodHandler>(&BasicSampleObject::Cat) } 49 }; 50 QStatus status = AddMethodHandlers(methodEntries, sizeof(methodEntries) / sizeof(methodEntries[0])); 51 if (ER_OK != status) { 52 printf("Failed to register method handlers for BasicSampleObject.\n"); 53 } 54 } 55 56 void ObjectRegistered() 57 { 58 BusObject::ObjectRegistered(); 59 printf("ObjectRegistered has been called.\n"); 60 } 61 62 63 void Cat(const InterfaceDescription::Member* member, Message& msg) 64 { 65 /* Concatenate the two input strings and reply with the result. */ 66 qcc::String inStr1 = msg->GetArg(0)->v_string.str; 67 qcc::String inStr2 = msg->GetArg(1)->v_string.str; 68 qcc::String outStr = inStr1 + inStr2; 69 70 MsgArg outArg("s", outStr.c_str()); 71 QStatus status = MethodReply(msg, &outArg, 1); 72 if (ER_OK != status) { 73 printf("Ping: Error sending reply.\n"); 74 } 75 } 76 }; 77 78 class MyBusListener : public BusListener, public SessionPortListener { 79 void NameOwnerChanged(const char* busName, const char* previousOwner, const char* newOwner) 80 { 81 if (newOwner && (0 == strcmp(busName, SERVICE_NAME))) { 82 printf("NameOwnerChanged: name=%s, oldOwner=%s, newOwner=%s.\n", 83 busName, 84 previousOwner ? previousOwner : "<none>", 85 newOwner ? newOwner : "<none>"); 86 } 87 } 88 bool AcceptSessionJoiner(SessionPort sessionPort, const char* joiner, const SessionOpts& opts) 89 { 90 if (sessionPort != SERVICE_PORT) { 91 printf("Rejecting join attempt on unexpected session port %d.\n", sessionPort); 92 return false; 93 } 94 printf("Accepting join session request from %s (opts.proximity=%x, opts.traffic=%x, opts.transports=%x).\n", 95 joiner, opts.proximity, opts.traffic, opts.transports); 96 return true; 97 } 98 }; 99 100 /** The bus listener object. */101 static MyBusListener s_busListener;102 103 /** Top level message bus object. */104 static BusAttachment* s_msgBus = NULL;105 106 /** Create the interface, report the result to stdout, and return the result status. */107 QStatus CreateInterface(void)108 {109 /* Add org.alljoyn.Bus.method_sample interface */110 InterfaceDescription* testIntf = NULL;111 QStatus status = s_msgBus->CreateInterface(INTERFACE_NAME, testIntf);112 113 if (status == ER_OK) {114 printf("Interface created.\n");115 testIntf->AddMethod("cat", "ss", "s", "inStr1,inStr2,outStr", 0);116 testIntf->Activate();117 } else {118 printf("Failed to create interface ‘%s‘.\n", INTERFACE_NAME);119 }120 121 return status;122 }123 124 /** Register the bus object and connect, report the result to stdout, and return the status code. */125 QStatus RegisterBusObject(BasicSampleObject* obj)126 {127 QStatus status = s_msgBus->RegisterBusObject(*obj);128 129 if (ER_OK == status) {130 printf("RegisterBusObject succeeded.\n");131 } else {132 printf("RegisterBusObject failed (%s).\n", QCC_StatusText(status));133 }134 135 return status;136 }137 138 /** Connect, report the result to stdout, and return the status code. */139 QStatus ConnectBusAttachment(void)140 {141 QStatus status = s_msgBus->Connect();142 143 if (ER_OK == status) {144 printf("Connect to ‘%s‘ succeeded.\n", s_msgBus->GetConnectSpec().c_str());145 } else {146 printf("Failed to connect to ‘%s‘ (%s).\n", s_msgBus->GetConnectSpec().c_str(), QCC_StatusText(status));147 }148 149 return status;150 }151 152 /** Start the message bus, report the result to stdout, and return the status code. */153 QStatus StartMessageBus(void)154 {155 QStatus status = s_msgBus->Start();156 157 if (ER_OK == status) {158 printf("BusAttachment started.\n");159 } else {160 printf("Start of BusAttachment failed (%s).\n", QCC_StatusText(status));161 }162 163 return status;164 }165 166 /** Create the session, report the result to stdout, and return the status code. */167 QStatus CreateSession(TransportMask mask)168 {169 SessionOpts opts(SessionOpts::TRAFFIC_MESSAGES, false, SessionOpts::PROXIMITY_ANY, mask);170 SessionPort sp = SERVICE_PORT;171 QStatus status = s_msgBus->BindSessionPort(sp, opts, s_busListener);172 173 if (ER_OK == status) {174 printf("BindSessionPort succeeded.\n");175 } else {176 printf("BindSessionPort failed (%s).\n", QCC_StatusText(status));177 }178 179 return status;180 }181 182 /** Advertise the service name, report the result to stdout, and return the status code. */183 QStatus AdvertiseName(TransportMask mask)184 {185 QStatus status = s_msgBus->AdvertiseName(SERVICE_NAME, mask);186 187 if (ER_OK == status) {188 printf("Advertisement of the service name ‘%s‘ succeeded.\n", SERVICE_NAME);189 } else {190 printf("Failed to advertise name ‘%s‘ (%s).\n", SERVICE_NAME, QCC_StatusText(status));191 }192 193 return status;194 }195 196 /** Request the service name, report the result to stdout, and return the status code. */197 QStatus RequestName(void)198 {199 const uint32_t flags = DBUS_NAME_FLAG_REPLACE_EXISTING | DBUS_NAME_FLAG_DO_NOT_QUEUE;200 QStatus status = s_msgBus->RequestName(SERVICE_NAME, flags);201 202 if (ER_OK == status) {203 printf("RequestName(‘%s‘) succeeded.\n", SERVICE_NAME);204 } else {205 printf("RequestName(‘%s‘) failed (status=%s).\n", SERVICE_NAME, QCC_StatusText(status));206 }207 208 return status;209 }210 211 /** Wait for SIGINT before continuing. */212 void WaitForSigInt(void)213 {214 while (s_interrupt == false) {215 #ifdef _WIN32216 Sleep(100);217 #else218 usleep(100 * 1000);219 #endif220 }221 }222 223 /** Main entry point */224 int main(int argc, char** argv, char** envArg)225 {226 printf("AllJoyn Library version: %s.\n", ajn::GetVersion());227 printf("AllJoyn Library build info: %s.\n", ajn::GetBuildInfo());228 229 /* Install SIGINT handler */230 signal(SIGINT, SigIntHandler);231 232 QStatus status = ER_OK;233 234 /* Create message bus */235 s_msgBus = new BusAttachment("myApp", true);236 237 if (!s_msgBus) {238 status = ER_OUT_OF_MEMORY;239 }240 241 if (ER_OK == status) {242 status = CreateInterface();243 }244 245 if (ER_OK == status) {246 s_msgBus->RegisterBusListener(s_busListener);247 }248 249 if (ER_OK == status) {250 status = StartMessageBus();251 }252 253 BasicSampleObject testObj(*s_msgBus, SERVICE_PATH);254 255 if (ER_OK == status) {256 status = RegisterBusObject(&testObj);257 }258 259 if (ER_OK == status) {260 status = ConnectBusAttachment();261 }262 263 /*264 * Advertise this service on the bus.265 * There are three steps to advertising this service on the bus.266 * 1) Request a well-known name that will be used by the client to discover267 * this service.268 * 2) Create a session.269 * 3) Advertise the well-known name.270 */271 if (ER_OK == status) {272 status = RequestName();273 }274 275 const TransportMask SERVICE_TRANSPORT_TYPE = TRANSPORT_ANY;276 277 if (ER_OK == status) {278 status = CreateSession(SERVICE_TRANSPORT_TYPE);279 }280 281 if (ER_OK == status) {282 status = AdvertiseName(SERVICE_TRANSPORT_TYPE);283 }284 285 /* Perform the service asynchronously until the user signals for an exit. */286 if (ER_OK == status) {287 WaitForSigInt();288 }289 290 /* Clean up msg bus */291 delete s_msgBus;292 s_msgBus = NULL;293 294 printf("Basic service exiting with status 0x%04x (%s).\n", status, QCC_StatusText(status));295 296 return (int) status;297 }
服务端主流程解析:
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;}
客户端完整代码:
1 #include <qcc/platform.h> 2 3 #include <assert.h> 4 #include <signal.h> 5 #include <stdio.h> 6 #include <vector> 7 8 #include <qcc/String.h> 9 10 #include <alljoyn/BusAttachment.h> 11 #include <alljoyn/version.h> 12 #include <alljoyn/AllJoynStd.h> 13 #include <alljoyn/Status.h> 14 15 using namespace std; 16 using namespace qcc; 17 using namespace ajn; 18 19 /** Static top level message bus object */ 20 static BusAttachment* g_msgBus = NULL; 21 22 /*constants*/ 23 static const char* INTERFACE_NAME = "org.alljoyn.Bus.sample"; 24 static const char* SERVICE_NAME = "org.alljoyn.Bus.sample"; 25 static const char* SERVICE_PATH = "/sample"; 26 static const SessionPort SERVICE_PORT = 25; 27 28 static bool s_joinComplete = false; 29 static SessionId s_sessionId = 0; 30 31 static volatile sig_atomic_t s_interrupt = false; 32 33 static void SigIntHandler(int sig) 34 { 35 s_interrupt = true; 36 } 37 38 /** AllJoynListener receives discovery events from AllJoyn */ 39 class MyBusListener : public BusListener, public SessionListener { 40 public: 41 void FoundAdvertisedName(const char* name, TransportMask transport, const char* namePrefix) 42 { 43 if (0 == strcmp(name, SERVICE_NAME)) { 44 printf("FoundAdvertisedName(name=‘%s‘, prefix=‘%s‘)\n", name, namePrefix); 45 46 /* We found a remote bus that is advertising basic service‘s well-known name so connect to it. */ 47 /* Since we are in a callback we must enable concurrent callbacks before calling a synchronous method. */ 48 g_msgBus->EnableConcurrentCallbacks(); 49 SessionOpts opts(SessionOpts::TRAFFIC_MESSAGES, false, SessionOpts::PROXIMITY_ANY, TRANSPORT_ANY); 50 QStatus status = g_msgBus->JoinSession(name, SERVICE_PORT, this, s_sessionId, opts); 51 if (ER_OK == status) { 52 printf("JoinSession SUCCESS (Session id=%d).\n", s_sessionId); 53 } else { 54 printf("JoinSession failed (status=%s).\n", QCC_StatusText(status)); 55 } 56 } 57 s_joinComplete = true; 58 } 59 60 void NameOwnerChanged(const char* busName, const char* previousOwner, const char* newOwner) 61 { 62 if (newOwner && (0 == strcmp(busName, SERVICE_NAME))) { 63 printf("NameOwnerChanged: name=‘%s‘, oldOwner=‘%s‘, newOwner=‘%s‘.\n", 64 busName, 65 previousOwner ? previousOwner : "<none>", 66 newOwner ? newOwner : "<none>"); 67 } 68 } 69 }; 70 71 /** Create the interface, report the result to stdout, and return the result status. */ 72 QStatus CreateInterface(void) 73 { 74 /* Add org.alljoyn.Bus.method_sample interface */ 75 InterfaceDescription* testIntf = NULL; 76 QStatus status = g_msgBus->CreateInterface(INTERFACE_NAME, testIntf); 77 78 if (status == ER_OK) { 79 printf("Interface ‘%s‘ created.\n", INTERFACE_NAME); 80 testIntf->AddMethod("cat", "ss", "s", "inStr1,inStr2,outStr", 0); 81 testIntf->Activate(); 82 } else { 83 printf("Failed to create interface ‘%s‘.\n", INTERFACE_NAME); 84 } 85 86 return status; 87 } 88 89 /** Start the message bus, report the result to stdout, and return the result status. */ 90 QStatus StartMessageBus(void) 91 { 92 QStatus status = g_msgBus->Start(); 93 94 if (ER_OK == status) { 95 printf("BusAttachment started.\n"); 96 } else { 97 printf("BusAttachment::Start failed.\n"); 98 } 99 100 return status;101 }102 103 /** Handle the connection to the bus, report the result to stdout, and return the result status. */104 QStatus ConnectToBus(void)105 {106 QStatus status = g_msgBus->Connect();107 108 if (ER_OK == status) {109 printf("BusAttachment connected to ‘%s‘.\n", g_msgBus->GetConnectSpec().c_str());110 } else {111 printf("BusAttachment::Connect(‘%s‘) failed.\n", g_msgBus->GetConnectSpec().c_str());112 }113 114 return status;115 }116 117 /** Register a bus listener in order to get discovery indications and report the event to stdout. */118 void RegisterBusListener(void)119 {120 /* Static bus listener */121 static MyBusListener s_busListener;122 123 g_msgBus->RegisterBusListener(s_busListener);124 printf("BusListener Registered.\n");125 }126 127 /** Begin discovery on the well-known name of the service to be called, report the result to128 stdout, and return the result status. */129 QStatus FindAdvertisedName(void)130 {131 /* Begin discovery on the well-known name of the service to be called */132 QStatus status = g_msgBus->FindAdvertisedName(SERVICE_NAME);133 134 if (status == ER_OK) {135 printf("org.alljoyn.Bus.FindAdvertisedName (‘%s‘) succeeded.\n", SERVICE_NAME);136 } else {137 printf("org.alljoyn.Bus.FindAdvertisedName (‘%s‘) failed (%s).\n", SERVICE_NAME, QCC_StatusText(status));138 }139 140 return status;141 }142 143 /** Wait for join session to complete, report the event to stdout, and return the result status. */144 QStatus WaitForJoinSessionCompletion(void)145 {146 unsigned int count = 0;147 148 while (!s_joinComplete && !s_interrupt) {149 if (0 == (count++ % 10)) {150 printf("Waited %u seconds for JoinSession completion.\n", count / 10);151 }152 153 #ifdef _WIN32154 Sleep(100);155 #else156 usleep(100 * 1000);157 #endif158 }159 160 return s_joinComplete && !s_interrupt ? ER_OK : ER_ALLJOYN_JOINSESSION_REPLY_CONNECT_FAILED;161 }162 163 /** Do a method call, report the result to stdout, and return the result status. */164 QStatus MakeMethodCall(void)165 {166 ProxyBusObject remoteObj(*g_msgBus, SERVICE_NAME, SERVICE_PATH, s_sessionId);167 const InterfaceDescription* alljoynTestIntf = g_msgBus->GetInterface(INTERFACE_NAME);168 169 assert(alljoynTestIntf);170 remoteObj.AddInterface(*alljoynTestIntf);171 172 Message reply(*g_msgBus);173 MsgArg inputs[2];174 175 inputs[0].Set("s", "Hello ");176 inputs[1].Set("s", "World!");177 178 QStatus status = remoteObj.MethodCall(SERVICE_NAME, "cat", inputs, 2, reply, 5000);179 180 if (ER_OK == status) {181 printf("‘%s.%s‘ (path=‘%s‘) returned ‘%s‘.\n", SERVICE_NAME, "cat",182 SERVICE_PATH, reply->GetArg(0)->v_string.str);183 } else {184 printf("MethodCall on ‘%s.%s‘ failed.", SERVICE_NAME, "cat");185 }186 187 return status;188 }189 190 /** Main entry point */191 int main(int argc, char** argv, char** envArg)192 {193 printf("AllJoyn Library version: %s.\n", ajn::GetVersion());194 printf("AllJoyn Library build info: %s.\n", ajn::GetBuildInfo());195 196 /* Install SIGINT handler. */197 signal(SIGINT, SigIntHandler);198 199 QStatus status = ER_OK;200 201 /* Create message bus. */202 g_msgBus = new BusAttachment("myApp", true);203 204 /* This test for NULL is only required if new() behavior is to return NULL205 * instead of throwing an exception upon an out of memory failure.206 */207 if (!g_msgBus) {208 status = ER_OUT_OF_MEMORY;209 }210 211 if (ER_OK == status) {212 status = CreateInterface();213 }214 215 if (ER_OK == status) {216 status = StartMessageBus();217 }218 219 if (ER_OK == status) {220 status = ConnectToBus();221 }222 223 if (ER_OK == status) {224 RegisterBusListener();225 status = FindAdvertisedName();226 }227 228 if (ER_OK == status) {229 status = WaitForJoinSessionCompletion();230 }231 232 if (ER_OK == status) {233 status = MakeMethodCall();234 }235 236 /* Deallocate bus */237 delete g_msgBus;238 g_msgBus = NULL;239 240 printf("Basic client exiting with status 0x%04x (%s).\n", status, QCC_StatusText(status));241 242 return (int) status;243 }
客户端主流程解析:
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(0)->v_string.str; qcc::String inStr2 = msg->GetArg(1)->v_string.str; qcc::String outStr = inStr1 + inStr2; MsgArg outArg("s", outStr.c_str()); QStatus status = MethodReply(msg, &outArg, 1); if (ER_OK != status) { printf("Ping: Error sending reply.\n"); }}
客户端方法调用的代码:
QStatus status = remoteObj.MethodCall(SERVICE_NAME, "cat", inputs, 2, reply, 5000);
说了这么多,这个代码的作用是干嘛呢,就是服务端提供一个连接字符串(str1+str2)的方法,并将结果返回给客户端。当然这只是一个很简单sample,如果你将你家电视定义了换台方法的话,用手机就可以通过调用这个方法进行控制了,当然前提是你的电视和手机在一个网内!
一个人学习有时挺没意思的,那就加入q群49073007一起交流讨论吧。
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。