UPnPの実装
    UDPでSSDPグループに参加する
    UDPでSSDPグループからデバイスを検索する
    TCPでルーターへリクエストを送る

UPnPを実装しよう

概要は説明した通りです。実際に実装してみましょう。サンプル実装を以下におきました。
実際に作ってもらうのが、もっとも効果的です。しかし、そんな時間がない方がほとんどでしょう。また、UPnP用のライブラリを利用するので、実装をする必要がないという方もいることでしょう。
なので、本章では実際に実装しながら、処理の流れを解説していきます
注意
Dart を利用するのてすが、Socket API は、hetimanetを使用します。2015/6/1において、Dart用に提供されている socketは、"chrome api ver1 " "chrome api ver2"、"dart:io"等いくつかあります。
利用するAPIに依存しないように、hetimanetでsocketを再定義して対応することにしました。

SSDPグループに参加する

通常、UDP Socketを生成して、IPが"239.255.255.250"、Portが"1900"のグループに参加します。 参加することで、SSDPグループに追加されたデバイス等が把握できるようになったり、グループに参加していないデバイスを無視したりできるようになります。
しかし、Chrome Socketから、上手く動作できなかったので、今回は、グループに参加していません。

(1) UDPソケットを生成する。

まずは、UDPソケットを生成しましょう。こんな感じです。
1
HetiSocketBuilder _socketBuilder = new HetiSocketBuilderChrome();
2
3
HetiUdpSocket _socket = _socketBuilder.createUdpClient();
4
_socket.onReceive().listen((HetiReceiveUdpInfo info) {
5
print("receive udp info");
6
});
7
8
_socket.bind("0.0.0.0", 0).then((int v){
9
if (v >=0) {
10
print("bind ok");
11
} else {
12
print("bind error");
13
}
14
}
Copied!
「bind ok」とコンソールに文字が表示されれば成功です。

(2) SSDPグループからデバイスを検索する

無事にUDPソケットを生成できる事を確認できたら、次はSSDPグループに、ポートマップに対応できるデバイスがないか依頼を出します。
1
_socket.send(
2
convert.UTF8.encode(SSDP_M_SEARCH_WANPPPConnectionV1),
3
SSDP_ADDRESS,
4
SSDP_PORT).then((HetiUdpSendInfo iii) {
5
print("send ok");
6
}).catchError((e) {
7
completer.completeError(e);
8
});
Copied!
先ほど生成したUDPSocketを利用して、"239.255.255.250"、Portが"1900"に 以下のメッセージを送っているだけです。
1
M-SEARCH * HTTP/1.1
2
MX: 3
3
HOST: 239.255.255.250:1900
4
MAN: "ssdp:discover"
5
ST: urn:schemas-upnp-org:service:WANIPConnection:1
Copied!
難しい事はないですね。これで、UPnPに対応したルーターが存在していれば、前の章で説明した。タグを含むxmlファイルを取得できます。

(3) グローバルIPを取得する

ルーターへ依頼をだせるようになりました。試しに、ルーターにGlobal IPについて問い合わせて見ましょう。
UPnPに対応しているルーターは、TCPサーバーが立ち上がっています。TCPサーバーへリクエストを送ります。
1
HetiHttpClient client = new HetiHttpClient(new HetiSocketBuilderChrome()));
2
client.connect(host, port).then((int v) {
3
return client.post(path, convert.UTF8.encode(body), {
4
KEY_SOAPACTION: soapAction,
5
"Content-Type": "text/xml"
6
});
7
}).then((HetiHttpClientResponse response) {
8
print("receive response");
9
}).catchError((e){
10
print("failed request");
11
});
Copied!
前章で説明した値を、pathとbodyに設定すれば無事リクエストを送信できます。

作成したライブラリは以下の通り

    ルータを発見する
    1
    UpnpDeviceSearcher
    2
    .createInstance(new hetimacl.HetiSocketBuilderChrome())
    3
    .then((hetima.UpnpDeviceSearcher searcher) {
    4
    searcher.onReceive().listen((hetima.UPnpDeviceInfo info) {
    5
    });
    6
    searcher.searchWanPPPDevice();
    7
    });
    Copied!
    ポートマッピングする
    1
    UpnpPPPDevice#addPortMapping(
    2
    localIP,
    3
    localPort,
    4
    remotePort,
    5
    UPnpPPPDevice.VALUE_PORT_MAPPING_PROTOCOL_TCP)
    6
    .then((UpnpPortMappingResult r) {
    7
    });
    Copied!
    グローバルアドレスを調べる
    1
    UpnpPPPDevice#requestGetExternalIPAddress()
    2
    .then((String address){
    3
    });
    Copied!
    ポートマッピングする
    1
    UpnpPPPDevice#addPortMapping(
    2
    localIP,
    3
    localPort,
    4
    remotePort,
    5
    UPnpPPPDevice.VALUE_PORT_MAPPING_PROTOCOL_TCP)
    6
    .then((UpnpPortMappingResult r) {
    7
    });
    Copied!
    グローバルアドレスを調べる
    1
    UpnpPPPDevice#requestGetExternalIPAddress()
    2
    .then((String address){
    3
    });
    Copied!
Kyorohiro work
Last modified 3yr ago