zoukankan      html  css  js  c++  java
  • 深入浅出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一起交流讨论吧。

  • 相关阅读:
    学习进度条
    软件工程期末总结
    实验四 主存空间的分配与回收
    学术诚信与道德
    《构建之法》第八、九、十章读后感
    实验三、进程调度模拟程序实验
    《构建之法》第六七章读后感
    Scrum团队成立3.0
    0428-项目再开发2.0
    作业调度模拟程序
  • 原文地址:https://www.cnblogs.com/alljoyn/p/3916535.html
Copyright © 2011-2022 走看看