转载:http://blog.sina.com.cn/s/blog_99f879b60101cw7s.html
Cling Core API:http://4thline.org/projects/cling/core/apidocs/
Cling 官网详细讲解:http://4thline.org/projects/cling/core/manual/cling-core-manual.xhtml#section.BasicAPI.ControlPoint
The programming interface of Cling is fundamentally the same for UPnP clients and servers. The single entry point for any program is the UpnpService
instance. Through this API you access the local UPnP stack, and either execute operations as a client (control point) or provide services to local or remote clients through the registry.
从根本上讲,Cling的编程接口对于UPnP的客户端和服务器相同。任何程序的单点登录都是UpnpService 实例。通过这个API你可以访问UPnP协议栈,不管选择操作一个客户端(控制点)或者通过注册表提供一个服务给本地或者远程客户端。
The following diagram shows the most important interfaces of Cling Core:
下图展现了Cling Core中最重要的接口。
You'll be calling these interfaces to work with UPnP devices and interact with UPnP services. Cling provides a fine-grained meta-model representing these artifacts:
通过这些接口,你可以与处理UPnP设备和与UPnP服务交互。Cling 提供了 fine-grained meta-model 代表了这些artifacts.
In this chapter we'll walk through the API and metamodel in more detail, starting with the UpnpService
.
这一章我们将详细介绍这些API和metamodel,首先以UpnpService开始。
The UpnpService
is an interface:
UpnpService是一个接口
public interface UpnpService {
public UpnpServiceConfiguration getConfiguration();
public ProtocolFactory getProtocolFactory();
public Router getRouter();
public ControlPoint getControlPoint();
public Registry getRegistry();
public void shutdown();
}
An instance of UpnpService
represents a running UPnP stack, including all network listeners, background maintenance threads, and so on. Cling Core bundles a default implementation which you can simply instantiate as follows:
一个UpnpService代表了运行一个UPnP协议栈,包括网络监听器,后台线程维护等。Cling Core 绑定了一些默认的实现,这些你都可以通过如下方法简单实例化。
UpnpService upnpService = new UpnpServiceImpl();
With this implementation, the local UPnP stack is ready immediately, it listens on the network for UPnP messages. You should call the shutdown()
method when you no longer need the UPnP stack. The bundled implementation will then cut all connections with remote event listeners and also notify all other UPnP participants on the network that your local services are no longer available. If you do not shutdown your UPnP stack, remote control points might think that your services are still available until your earlier announcements expire.
通过这样的实现,本地UPnP协议栈马上运行,它坚挺网络中的UPnP消息。当你不需要UPnP协议栈时,你可以调用 shutdown()方法。绑定的实现将切断与远程时间接听器的联系,而且会通知网络上所有的UPnP参与者你的本地服务不在可用。如果你不关闭UPnP协议栈,远程控制点可能会认为你的服务一直可用直到之前的宣告过期。
The bundled implementation offers two additional constructors:
绑定的实现提供了两种构造函数
UpnpService upnpService = new UpnpServiceImpl(RegistryListener... registryListeners);
This constructor accepts your custom RegistryListener
instances, which will be activated immediately even before the UPnP stack listens on any network interface. This means that you can be notified of all incoming device and service registrations as soon as the network stack is ready. Note that this is rarely useful, you'd typically send search requests after the stack is up and running anyway - after adding listeners to the registry.
构造函数接受你的 RegistryListener 实例,它将被立即激活,甚至早于UPnP协议栈坚挺网络接口。这意味着当网络协议栈准备好时,你能够通知所有的设备和服务的注册信息。注意 这些很少有用,在协议栈开始运行后,你往往需要发送搜索请求。
The second constructor supports customization of the UPnP stack configuration:
第二个构造函数支持自定义的UPnP协议栈配置
UpnpService upnpService = new UpnpServiceImpl(new DefaultUpnpServiceConfiguration(8081));
This example configuration will change the TCP listening port of the UPnP stack to 8081
, the default being an ephemeral (system-selected free) port. The UpnpServiceConfiguration
is also an interface, in the example above you can see how the bundled default implementation is instantiated.
这个配置例子将改变TCP监听的UPnP协议端口成为8081.这将默认为临时端口。 UpnpServiceConfiguration 是一个借口,在你之前看到的例子中你能看到 默认的绑定实实现如何实例化的。
The following section explain the methods of the UpnpService
interface and what they return in more detail.
下面一节解释UpnpService 接口的方法 以及返回值的详细信息。
This is the configuration interface of the default UPnP stack in Cling Core, an instance of which you have to provide when creating the UpnpServiceImpl
:
这是Cling Core 中默认UPnP 协议栈的默认配置接口,当你生成一个UpnpServiceImpl时,你必须提供一个配置接口。
public interface UpnpServiceConfiguration {
// NETWORK
public NetworkAddressFactory createNetworkAddressFactory();
public DatagramProcessor getDatagramProcessor();
public SOAPActionProcessor getSoapActionProcessor();
public GENAEventProcessor getGenaEventProcessor();
public StreamClient createStreamClient();
public MulticastReceiver createMulticastReceiver(NetworkAddressFactory naf);
public DatagramIO createDatagramIO(NetworkAddressFactory naf);
public StreamServer createStreamServer(NetworkAddressFactory naf);
public Executor getMulticastReceiverExecutor();
public Executor getDatagramIOExecutor();
public Executor getStreamServerExecutor();
// DESCRIPTORS
public DeviceDescriptorBinder getDeviceDescriptorBinderUDA10();
public ServiceDescriptorBinder getServiceDescriptorBinderUDA10();
// PROTOCOL
public Executor getAsyncProtocolExecutor();
public Executor getSyncProtocolExecutor();
// REGISTRY
public Namespace getNamespace();
public Executor getRegistryMaintainerExecutor();
public Executor getRegistryListenerExecutor();
}
This is quite an extensive SPI but you typically won't implement it from scratch. Overriding and customizing the bundled DefaultUpnpServiceConfiguration
should suffice in most cases.
这是一个扩展的SPI,然而你往往不需要实现……。覆盖或者配置这些绑定的 DefaultUpnpServiceConfiguration 在大多数情况下已经足够。
The configuration settings reflect the internal structure of Cling Core:
配置设置反映了Cling Core的内部结构。
Network
The NetworkAddressFactory
provides the network interfaces, ports, and multicast settings which are used by the UPnP stack. At the time of writing, the following interfaces and IP addresses are ignored by the default configuration: any IPv6 interfaces and addresses, interfaces whose name starts with "vmnet", and the local loopback. Otherwise, all interfaces and their TCP/IP addresses are used and bound.
NetworkAddressFactory 提供了UPnP协议栈需要的网络接口,端口和广播配置。在编写的时候,一下的接口的IP地址在默认下是被忽视的:任何IPV6接口和地址,任何以vmnet为开始名字的接口,还有本地会还。否则,所有的接口和TCP/IP地址都被使用和约束。
You can set the system property org.teleal.cling.network.useInterfaces
to provide a comma-separated list of network interfaces you'd like to bind excusively. Additionally, you can restrict the actual TCP/IP addresses to which the stack will bind with a comma-separated list of IP address provided through the org.teleal.cling.network.useAddresses
system property.
你可以设置系统配置 org.teleal.cling.network.useInterfaces 来提供comma-separated 的网络接口列表。额外的,你能限制的实际TCP/IP地址,通过org.teleal.cling.network.useAddresses 系统配置,
协议栈将绑定一些地址列表。
Furthermore, the configuration declares the network-level message listeners and senders, that is, the implementations used by the network Router
.
而且,配置声明了网络级别的消息监听器和发送者,即,通过网络路由器实现。
Stream messages are TCP HTTP requests and responses, the bundled implementation will use the Sun JDK 6.0 webserver to listen for HTTP requests, and it sends HTTP requests through the standard JDKHttpURLConnection
.
消息了是 TCP HTTP 请求和 回应,绑定的实现将使用 Sun JDK6.0 webserver 来坚挺HTTP请求,它发送HTTP请求使用标准的 JDK HttpURLConnection
UDP unicast and multicast datagrams are received, parsed, and send by a custom implementation bundled with Cling Core that does not require any particular Sun JDK classes.
UDP 单播和广播数据报被接受,解析,通过绑定了Cling Core的客户实现发送。
Descriptors 描述
Reading and writing UPnP XML descriptors is handled by binders, you can provide alternative implementations if necessary.
通过binder 读取和编写 UPnP XML 描述,如果有必要你可以提供必要的替代品
Executors
The Cling UPnP stack is multi-threaded, thread creation and execution is handled through java.util.concurrent
executors. The default configuration uses a pool of threads with a maximum size of 64 concurrently running threads, which should suffice for even very large installations. Executors can be configured fine-grained, for network message handling, actual UPnP protocol execution (handling discovery, control, and event procedures), and local registry maintenance and listener callback execution. Most likely you will not have to customize any of these settings.
Cling UPnP协议栈是多线程的,通过java.util.concurrent
executors 生成和执行线程。默认的配置是使用最大为64的线程池来运行线程,这对于大型装置是足够的。执行者能够被配置的 fine0grained,因为网络消息处理,实际UPnP协议执行(处理 发现,控制,和事件触发过程),本地注册表维护和监听器回调执行。你讲不用自己配置任何的相关配置。
If you are trying to use Cling Core in a runtime container such as Tomcat, JBoss AS, or Glassfish, you might run into an error on startup. The error tells you that Cling couldn't use the Java JDK'sHTTPURLConnection
for HTTP client operations. This is an old and badly designed part of the JDK: Only "one application" in the whole JVM can configure it. If your container is already using the HTTPURLConnection
, you have to switch Cling to an alternative HTTP client, e.g. the other bundled implementation based on Apache HTTP Core.
如果你想使用Cling Core 到运行容器中,例如Tomcat ,JBoss AS,或者 Glassfish,你可能会在开始时遇到错误。错误消息显示 Cling 不能为HTTP客户端操作使用JAVA JDK 的 HTTPURLConnection 。这是一个老的 很坏的JDK设计:JVM中只有一个 程序能配置它。如果你的容器已经可以使用HTTPURLConnection,你需要把Cling 转移到一个替换的 HTTP客户端,其他基于Apache HTTP内核的实现。
Furthermore, as mentioned earlier, Cling Core provides HTTP services using, by default, the SUN JDK 6.x bundled webserver. If you are not deploying with the Sun JDK, or if you also switched the HTTP client already to Apache HTTP Core, you probably also have or want to switch the HTTP server.
而且,像之前提过的,Cling Core 提供HTTP 服务,默认使用SUN JDK6.X 绑定的webserver。如果你没有部署sun 的JDK,或者你也转换 HTTP client 成Apache HTTP Core,你需要 转换HTTP 服务器。
This is how you override the default network transport configuration:
这是如何覆盖默认的网络传输配置
...
import org.teleal.cling.transport.impl.apache.StreamClientConfigurationImpl;
import org.teleal.cling.transport.impl.apache.StreamClientImpl;
import org.teleal.cling.transport.impl.apache.StreamServerConfigurationImpl;
import org.teleal.cling.transport.impl.apache.StreamServerImpl;
public class MyUpnpServiceConfiguration extends DefaultUpnpServiceConfiguration {
@Override
public StreamClient createStreamClient() {
return new StreamClientImpl(new StreamClientConfigurationImpl());
}
@Override
public StreamServer createStreamServer(NetworkAddressFactory networkAddressFactory) {
return new StreamServerImpl(
new StreamServerConfigurationImpl(
networkAddressFactory.getStreamListenPort()
)
);
}
}
Don't forget to add the Apache HTTP Core libraries to your classpath or as dependencies in yourpom.xml
!
不要忘记添加Apache HTTP 内核库到你的 classpath 或者依赖你的pom.xml
Cling Core internals are modular and any aspect of the UPnP protocol is handled by an implementation (class) which can be replaced without affecting any other aspect. TheProtocolFactory
provides implementations, it is always the first access point for the UPnP stack when a message which arrives on the network or an outgoing message has to be handled:
Cling Core 的内部是模块化的,UPnP协议的任何一方面变化都由一个实现来处理,这样不会影响到任何其他方面。ProtocolFactory 提供了一些实现,当网络中的消息或者输出信息被处理时,这往往是UPnP协议栈第一个接入点。
public interface ProtocolFactory {
public ReceivingAsync createReceivingAsync(IncomingDatagramMessage message)
throws ProtocolCreationException;;
public ReceivingSync createReceivingSync(StreamRequestMessage requestMessage);
throws ProtocolCreationException;;
public SendingNotificationAlive createSendingNotificationAlive(LocalDevice ld);
public SendingNotificationByebye createSendingNotificationByebye(LocalDevice ld);
public SendingSearch createSendingSearch(UpnpHeader searchTarget);
public SendingAction createSendingAction(ActionInvocation invocation, URL url);
public SendingSubscribe createSendingSubscribe(RemoteGENASubscription s);
public SendingRenewal createSendingRenewal(RemoteGENASubscription s);
public SendingUnsubscribe createSendingUnsubscribe(RemoteGENASubscription s);
public SendingEvent createSendingEvent(LocalGENASubscription s);
}
This API is a low-level interface that allows you to access the internals of the UPnP stack, in the rare case you need to manually trigger a particular procedure.
这个API是一个 低级别的接口,允许你访问UPnP协议栈的内部,一般很少需要你手动触发一个特定的过程。
The first two methods are called by the networking code when a message arrives, either multicast or unicast UDP datagrams, or a TCP (HTTP) stream request. The default protocol factory implementation will then pick the appropriate receiving protocol implementation to handle the incoming message.
当一个消息到达,不管是多播或者单播UDP数据报,或者 TCP HTTP 请求流,有两个方法将被网络代码调用。默认的协议工厂实现将选取合适的“接受协议实现”来处理这些消息。
The local registry of local services known to the UPnP stack naturally also sends messages, such as alive and byebye notifications. Also, if you write a UPnP control point various search, control, and eventing messages are send by the local UPnP stack. The protocol factory decouples the message sender (registry, control point) from the actual creation, preparation, andtransmission of the messages.
UPnP协议栈知道的本地服务的注册表自然也要发送消息,例如 alive 和 byebye通知。同样,如果你写一个UPnP控制点通过本地UPnP协议栈发送搜索,控制,事件触发消息,协议工厂分离消息发送者(注册表,控制点)与他们消息的实际生成,准备,传送。
Transmission and reception of messages at the lowest-level is the job of the network Router
.
低级别的传送和接受消息是网络路由器的工作。
The reception and sending of messages, that is, all message transport, is encapsulated through the Router
interface:
public interface Router {
public void received(IncomingDatagramMessage msg);
public void received(UpnpStream stream);
public void send(OutgoingDatagramMessage msg);
public StreamResponseMessage send(StreamRequestMessage msg);
public void broadcast(byte[] bytes);
}
UPnP works with two types of messages: Multicast and unicast UDP datagrams which are typically handled asynchronously, and request/response TCP messages with an HTTP payload. The Cling Core bundled RouterImpl
will instantiate and maintain the listeners for incoming messages as well as transmit any outgoing messages.
UPnP处理两种类型的消息:通常以异步方式处理多播或者单播UDP数据报,以HTTP payload方式处理tcp 请求/回应消息。Cling Core 绑定的 RouterImpl 将实例化并维持监听器来处理 接入和发出的消息。
The actual implementation of a message receiver which listens on the network or a message sender is provided by the UpnpServiceConfiguration
, which we have introduced earlier. You can access the Router
directly if you have to execute low-level operations on the network layer of the UPnP stack.
用来监听网络或者消息发送者的消息接收器通过UpnpServiceConfiguration来实际实现。如果你必须执行UPnP协议栈低级别的的网络操作,你可以直接访问路由器。
Most of the time you will however work with the ControlPoint
and Registry
interfaces to interact with the UPnP stack.
大多数时候,你将需要 处理 ControlPoint 和 Registry 接口来实现与UPnP协议栈的交互。