首页 > 代码库 > 深入浅出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一起交流讨论吧。