Constrained Application Protocol
IoTで求められる省電力に対応するプロトコルとして、Constrained Application Protocol 略してCoAPと呼ばれるものがあります。
UDPを使用しヘッダおよび通信制御の容量を削減し、フォーマットとしてHTTPとのマッチングを可能としているところが特徴ですが、HTTPライクな割にクライアントからサーバへのリクエストだけではなく、サーバから定期的にデータをPUSHされる"observe"という機能があったり、プロトコルの実装としては複雑です。
ただ一般には決して利用されないようなこのCoAPにもいくつかのフレームワークが存在し、実装に悩む必要はありません。
今回はフレームワークの一つであるCaliforniumを利用したサーバのサンプルプログラムを作成します。
build.gradle
gradleでCaliforniumをビルドします。Eclipseのプロジェクトであっても、IDEはIntellijでも当然動作します。
dependencies { compile 'org.eclipse.californium:californium-core:2.3.0' compile 'org.slf4j:slf4j-log4j12:1.7.30' }
Californiumだけビルドすれば動作に問題はありませんが、それだけだと動作時にログ出力先がないとエラーがでるのでslf4jもビルドしておきます。
リクエスト受信時の動作設定
指定パスへのリクエスト
指定されたパス(例えば"coap://localhost/Hello")にリクエストを受信した場合の動作を記述します。
CoapResourceクラスにパス名を渡すことでパスを設定します。
class HelloResource extends CoapResource { public HelloResource() { super("Hello"); //パスの指定 } @Override public void handleGET(CoapExchange exchange) { //応答動作。この場合は"World"を返信。 exchange.respond("World"); } }
observeリクエスト
observeのRegistrationを受信した場合の動作を記述します。 Timerで応答周期を設定している点を除き、通常のパス指定のときと記述内容は変わりません。
public class ObservableResource extends CoapResource { private String currentTimeString; static final private SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public ObservableResource() { super("obs"); //パスの指定 setObservable(true); setObserveType(CoAP.Type.CON); Timer timer = new Timer(); //応答周期設定 timer.schedule(new TimerTask() { @Override public void run() { resetCurrentTIme(); changed(); } }, 0, 5000); } private void resetCurrentTIme() { Date currentDate = new Date(); currentTimeString = DATE_FORMAT.format(currentDate); } @Override public void handleGET(CoapExchange exchange) { ////応答動作。この場合は現在時刻を返信。 exchange.respond(currentTimeString); } }
mainクラス
サーバの受信IPアドレスを設定し、パスごとのリクエストクラスを追加します。
public class CaliforniumServer extends CoapServer { private static final int COAP_PORT = NetworkConfig.getStandard().getInt(NetworkConfig.Keys.COAP_PORT); public static void main(String[] args) { CaliforniumServer server = new CaliforniumServer(); server.addEndpoints(); //パスごとの受信動作追加 ObservableResource observable = new ObservableResource(); HelloResource hello = new HelloResource(); server.add(observable, hello); server.start(); } private void addEndpoints() { Collection<InetAddress> addresses = addresses = NetworkInterfacesUtil.getNetworkInterfaces(); NetworkConfig config = NetworkConfig.getStandard(); for(InetAddress address : addresses) { InetSocketAddress bindToAddress = new InetSocketAddress(address, COAP_PORT); System.out.println(bindToAddress.toString()); CoapEndpoint.Builder builder = new CoapEndpoint.Builder(); builder.setInetSocketAddress(bindToAddress); builder.setNetworkConfig(config); addEndpoint(builder.build()); } } }