深入浅出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.
");
 53         }
 54     }
 55 
 56     void ObjectRegistered()
 57     {
 58         BusObject::ObjectRegistered();
 59         printf("ObjectRegistered has been called.
");
 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.
");
 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.
",
 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.
", sessionPort);
 92             return false;
 93         }
 94         printf("Accepting join session request from %s (opts.proximity=%x, opts.traffic=%x, opts.transports=%x).
",
 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.
");
115         testIntf->AddMethod("cat", "ss",  "s", "inStr1,inStr2,outStr", 0);
116         testIntf->Activate();
117     } else {
118         printf("Failed to create interface '%s'.
", 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.
");
131     } else {
132         printf("RegisterBusObject failed (%s).
", 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.
", s_msgBus->GetConnectSpec().c_str());
145     } else {
146         printf("Failed to connect to '%s' (%s).
", 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.
");
159     } else {
160         printf("Start of BusAttachment failed (%s).
", 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.
");
175     } else {
176         printf("BindSessionPort failed (%s).
", 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.
", SERVICE_NAME);
189     } else {
190         printf("Failed to advertise name '%s' (%s).
", 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.
", SERVICE_NAME);
204     } else {
205         printf("RequestName('%s') failed (status=%s).
", 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 _WIN32
216         Sleep(100);
217 #else
218         usleep(100 * 1000);
219 #endif
220     }
221 }
222 
223 /** Main entry point */
224 int main(int argc, char** argv, char** envArg)
225 {
226     printf("AllJoyn Library version: %s.
", ajn::GetVersion());
227     printf("AllJoyn Library build info: %s.
", 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 discover
267      *    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).
", 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')
", 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).
", s_sessionId);
 53             } else {
 54                 printf("JoinSession failed (status=%s).
", 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'.
",
 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.
", INTERFACE_NAME);
 80         testIntf->AddMethod("cat", "ss",  "s", "inStr1,inStr2,outStr", 0);
 81         testIntf->Activate();
 82     } else {
 83         printf("Failed to create interface '%s'.
", 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.
");
 96     } else {
 97         printf("BusAttachment::Start failed.
");
 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'.
", g_msgBus->GetConnectSpec().c_str());
110     } else {
111         printf("BusAttachment::Connect('%s') failed.
", 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.
");
125 }
126 
127 /** Begin discovery on the well-known name of the service to be called, report the result to
128    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.
", SERVICE_NAME);
136     } else {
137         printf("org.alljoyn.Bus.FindAdvertisedName ('%s') failed (%s).
", 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.
", count / 10);
151         }
152 
153 #ifdef _WIN32
154         Sleep(100);
155 #else
156         usleep(100 * 1000);
157 #endif
158     }
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'.
", 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.
", ajn::GetVersion());
194     printf("AllJoyn Library build info: %s.
", 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 NULL
205      * 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).
", status, QCC_StatusText(status));
241 
242     return (int) status;
243 }

客户端主流程解析:

int main(int argc, char** argv, char** envArg)
{
    printf("AllJoyn Library version: %s.
", ajn::GetVersion());
    printf("AllJoyn Library build info: %s.
", 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).
", 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.
");
        }
}

客户端方法调用的代码:

QStatus status = remoteObj.MethodCall(SERVICE_NAME, "cat", inputs, 2, reply, 5000);

  说了这么多,这个代码的作用是干嘛呢,就是服务端提供一个连接字符串(str1+str2)的方法,并将结果返回给客户端。当然这只是一个很简单sample,如果你将你家电视定义了换台方法的话,用手机就可以通过调用这个方法进行控制了,当然前提是你的电视和手机在一个网内!

一个人学习有时挺没意思的,那就加入q群49073007一起交流讨论吧。

原文地址:https://www.cnblogs.com/alljoyn/p/3916535.html