金曜日, 3月 23, 2007

続 bonjour by Java

次は、Bonjourを使ってローカルリンク上にサービスを通知してみます。

今回通知するサービスは、_testとし、このサービスはTCPの6666番ポートを使っていると仮定します。

さらに、サービスを行っているノードを識別するインスタンス名を_QuBEとします。

すなわち、_QuBE._test._tcp.localとしてサービスを通知します。

このプログラムは以下のようになります。

import com.apple.dnssd.*;

public class Main implements RegisterListener {
DNSSDRegistration r;

public Main() {
}

public void serviceRegistered(DNSSDRegistration registration, int flags,
String serviceName, String regType, String domain) {
System.out.println("serviceName = " + serviceName);
System.out.println("regType = " + regType);
System.out.println("domain = " + domain);
}

public void operationFailed(DNSSDService service, int errorCode) {

}

public void register(String name, int port) {
try {
r = DNSSD.register(name, "_test._tcp", port, this);
} catch (Exception e){
e.printStackTrace();
System.exit(-1);
}
}

public static void main(String[] args) {
Main m = new Main();

m.register("QuBE", 6666);

for (;;) {
try {
Thread.sleep(100);
} catch (Exception e){
e.printStackTrace();
System.exit(-1);
}
}
}
}

DNSSD.register(name, "_test._tcp", port, this); が、サービスを通知、登録するための関数になります。
ここでは、nameがサービスのインスタンス名、"_test._tcp"がサービスタイプ、portがそのサービスを提供しているポート番号となります。
最後の引数、thisでは、リスナクラスを登録する必要があり、このクラスはRegisterListenerインターフェースをインプリメントしていなければいけません。

RegisterListenerインターフェースをインプリメントするには、serviceRegistered関数と、operationFailed関数を定義する必要があります。
これらは、サービスの登録が成功したとき、もしくは失敗したときに呼び出されます。

それでは、このプログラムを実行してみます。

実行する前に、dns-sdをターミナルで動かしておきます
% dns-sd -B _test._tcp

この後、上記プログラムを実行すると、dns-sdでは、以下のようなメッセージが表示されます。
Browsing for _test._tcp
Timestamp A/R Flags if Domain Service Type Instance Name
13:07:47.146 Add 2 8 local. _test._tcp. QuBE
13:07:47.148 Add 2 9 local. _test._tcp. QuBE
13:07:47.148 Add 2 5 local. _test._tcp. QuBE

また、プログラムの実行結果は以下のようになります。
serviceName = QuBE
regType = _test._tcp.
domain = local.

月曜日, 3月 19, 2007

bonjour by Java

BonjourをJavaで使ってみます。
Bonjourの詳しい説明はこちら(Wikipedia)。

Bonjourでは、サービスタイプという概念があります。
たとえば、iTunesでは、_daap._tcpというサービスタイプが用いられています。
他には、_http._tcpや、_printer._udpなどがあります。

PCは_http._tcpというサービスを提供していることを、リンクローカルマルチキャスを用いて知らせます。

dns-sdを利用すると、同一セグメント上に流れてきているサービスを、表示することができます。
例えば、_daap._tcpというサービスが流れてきているかどうかを表示するには以下のようにします。
 % dns-sd -B _daap._tcp

この後、iTunesを起動してみると、次のようなメッセージが表示されます。
Browsing for _daap._tcp
Timestamp A/R Flags if Domain Service Type Instance Name
3:03:01.323 Add 3 8 local. _daap._tcp. QuBE
3:03:01.324 Add 3 9 local. _daap._tcp. QuBE
3:03:01.324 Add 2 5 local. _daap._tcp. QuBE

次に、これと似たようなことを、Javaで実装してみます。
コードは以下のようになります。
import java.util.*;
import com.apple.dnssd.*;

public class bonjourTest implements BrowseListener {

public bonjourTest() {}

public void serviceFound(DNSSDService browser, int flags, int ifIndex,
String serviceName, String regType, String domain) {
System.out.println("Sercice Founded");
System.out.println("name = " + serviceName);
System.out.println("registered type = " + regType);
System.out.println("domain = " + domain);
}

public void serviceLost(DNSSDService browser, int flags, int ifIndex,
String serviceName, String regType, String domain) {
System.out.println("Service Lost");
System.out.println("name = " + serviceName);
System.out.println("name = " + serviceName);
System.out.println("registered type = " + regType);
System.out.println("domain = " + domain);
}

public void operationFailed(DNSSDService service, int errorCode) {

}

public static void main (String args[]) {
bonjourTest b = new bonjourTest();

try {
DNSSD.browse("_daap._tcp", b);

for (;;) {
Thread.sleep(1000);
}
} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
}
}

DNSSD::browse() 関数を用いて、取得するサービスタイプを指定し、サービスが取得されたときのリスナクラスを指定します。
このリスナクラスは、BrowseListenerインターフェースをインプリメントし、serviceFound(), serviceLost(), operationFailed()関数を定義することで出来上がります。

DNSSDクラスはファクトリクラスとなっており、ここで定義された関数を用いることで、サービスの登録なども行えます。

上記のプログラムを実行して、iTunesを起動すると、以下のようなメッセージが表示されます。
Sercice Founded
name = QuBE
registered type = _daap._tcp.
domain = local.
Sercice Founded
name = QuBE
registered type = _daap._tcp.
domain = local.
Sercice Founded
name = QuBE
registered type = _daap._tcp.
domain = local.