📄 client-tutorial.xml
字号:
<?xml version="1.0"?><!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"><chapter id="client-tutorial"> <title>Writing a UPnP Client</title> <simplesect> <title>Introduction</title> <para> This chapter explains how to write an application which fetches the external IP address from an UPnP-compliant modem. To do this a <glossterm>Control Point</glossterm> is created, which searches for services of the type <literal>urn:schemas-upnp-org:service:WANIPConnection:1</literal> (part of the <ulink url="http://upnp.org/standardizeddcps/igd.asp">Internet Gateway Device</ulink> specification). As services are discovered <firstterm>Service Proxy</firstterm> objects are created by GUPnP to allow interaction with the service, on which we can invoke the action <function>GetExternalIPAddress</function> to fetch the external IP address. </para> </simplesect> <simplesect> <title>Finding Services</title> <para> First, we initialize GUPnP and create a control point targeting the service type. Then we connect a signal handler so that we are notified when services we are interested in are found. </para> <programlisting>#include <libgupnp/gupnp-control-point.h>static GMainLoop *main_loop;intmain (int argc, char **argv){ GUPnPContext *context; GUPnPControlPoint *cp; /* Required initialisation */ g_thread_init (NULL); g_type_init (); /* Create a new GUPnP Context. By here we are using the default GLib main context, and connecting to the current machine's default IP on an automatically generated port. */ context = gupnp_context_new (NULL, NULL, 0, NULL); /* Create a Control Point targeting WAN IP Connection services */ cp = gupnp_control_point_new (context, "urn:schemas-upnp-org:service:WANIPConnection:1"); /* The service-proxy-available signal is emitted when any services which match our target are found, so connect to it */ g_signal_connect (cp, "service-proxy-available", G_CALLBACK (service_proxy_available_cb), NULL); /* Tell the Control Point to start searching */ gssdp_resource_browser_set_active (GSSDP_RESOURCE_BROWSER (cp), TRUE); /* Enter the main loop. This will start the search and result in callbacks to service_proxy_available_cb. */ main_loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (main_loop); /* Clean up */ g_main_loop_unref (main_loop); g_object_unref (cp); g_object_unref (context); return 0;}static voidservice_proxy_available_cb (GUPnPControlPoint *cp, GUPnPServiceProxy *proxy){ /* … */}</programlisting> </simplesect> <simplesect> <title>Invoking Actions</title> <para> Now we have an application which searches for the service we specified and calls <function>service_proxy_available_cb</function> for each one it found. To get the external IP address we need to invoke the <literal>GetExternalIPAddress</literal> action. This action takes no in arguments, and has a single out argument called "NewExternalIPAddress". GUPnP has a set of methods to invoke actions (which will be very familiar to anyone who has used <literal>dbus-glib</literal>) where you pass a <constant>NULL</constant>-terminated varargs list of (name, GType, value) tuples for the in arguments, then a <constant>NULL</constant>-terminated varargs list of (name, GType, return location) tuples for the out arguments. </para> <programlisting>static voidservice_proxy_available_cb (GUPnPControlPoint *cp, GUPnPServiceProxy *proxy){ GError *error = NULL; char *ip = NULL; gupnp_service_proxy_send_action (proxy, /* Action name and error location */ "GetExternalIPAddress", &error, /* IN args */ NULL, /* OUT args */ "NewExternalIPAddress", G_TYPE_STRING, &ip, NULL); if (error == NULL) { g_print ("External IP address is %s\n", ip); g_free (ip); } else { g_printerr ("Error: %s\n", error->message); g_error_free (error); } g_main_loop_quit (main_loop);}</programlisting> <para> Note that <link linkend="gupnp-service-proxy-send-action"><function>gupnp_service_proxy_send_action()</function></link> blocks until the service has replied. If you need to make non-blocking calls then use <link linkend="gupnp-service-proxy-begin-action"><function>gupnp_service_proxy_begin_action()</function></link>, which takes a callback that will be called from the mainloop when the reply is received. </para> </simplesect> <simplesect> <title>Generating Wrappers</title> <para> After making several method calls using <link linkend="gupnp-service-proxy-send-action"><function>gupnp_service_proxy_send_action()</function></link> can become tedious, because of the requirement to specify the types. An alternative is to use <xref linkend="gupnp-binding-tool"/>, which generates wrappers which hide the boilerplate code from you. Using the generated wrapper would replace <link linkend="gupnp-service-proxy-send-action"><function>gupnp_service_proxy_send_action()</function></link> with this code: </para> <programlisting>GetExternalIPAddress (proxy, &ip, &error);</programlisting> </simplesect></chapter>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -