JavaでのStream Control Transport Protocol(SCTP)

Chris Hegarty、2009年6月

JavaでのStream Control Transport Protocol(SCTP)のサポートが、JDK 7の機能として承認されました。 APIとリファレンス実装の定義は、OpenJDK SCTPプロジェクトを通して実施されました。 この作業はJDK 7 マイルストーン3に統合されており、将来のすべての拡張で利用できます。

SCTPの概要

Stream Control Transport Protocol(SCTP)は、信頼性に優れたメッセージ指向のトランスポート・プロトコルであり、UDP(User Datagram Protocol)およびTCP(Transmission Control Protocol)と同じ階層に位置します。 SCTPはセッション指向であり、データを転送する前にエンドポイント間のアソシエーションを確立する必要があります。

SCTPはマルチホーミングを直接サポートしています。つまり、エンドポイントを複数のアドレスで表すことができ、各アドレスをデータの送受信に使用できます。このため、ネットワークの冗長性が確保されます。 2つのエンドポイント間のコネクションは、これらのエンドポイント間のアソシエーションと呼ばれます。 エンドポイントは、アソシエーション設定中にアドレスのリストを交換できます。 1つのアドレスがプライマリ・アドレスとして指定されます。これが、ピア・エンドポイントがデータの送信に使用するデフォルト・アドレスとなります。 あるエンドポイントの特定のセッションでは、アドレス・リスト全体で単一のポート番号が使用されます。

SCTPはメッセージベースです。 I/O処理はメッセージに対して行われ、メッセージ間の境界が維持されます。 各アソシエーションは複数の独立した論理ストリームをサポートできます。 各ストリームは、単一のアソシエーション内部におけるメッセージ・シーケンスを表し、ストリームは互いに独立しています。つまり、ストリーム識別子とシーケンス番号がデータ・パケットに含まれており、ストリームごとにメッセージのシーケンスを設定できます。

SCTPのおもな機能

  • メッセージ・フレーミング
  • 信頼性の高いトランスポート・サービス
  • セッション指向
  • 順序あり/順序なしのメッセージ配信
  • マルチホーミング
    • 2つのエンドポイント間のアソシエーション
    • 各エンドポイントは複数のIPアドレスで表すことが可能
    • フェイルオーバーと冗長性を確保
  • マルチストリーミング
    • データを複数のストリームにパーティション化
    • 独立したシーケンス配信
  • ヘッドオブライン・ブロッキングを回避

JDK 7でのSCTPのサポート

Java APIは、NIOチャネル・フレームワークをベースとしています。このため、SCTPを必要とするアプリケーションは、ブロッキングなしの多重化I/Oを活用できます。新しいクラス/インタフェースを格納するための新しいパッケージcom.sun.nio.sctpが定義されています。 パッケージ名はcom.sun.nio.sctpです。java.nio.channels.sctpなどの形式にはなっていません。

この違いは、APIと実装は完全にサポートされ公開されますが、Java SEプラットフォームには含まれないことを表しています。 業界でSCTPに関する経験がもっと積まれた後に、標準APIが定義できることになります。

このパッケージ内のメイン・クラスは、新しい3種類のチャネル・タイプを表します。 これらの新しいチャネルは、2つの論理グループに分類できます。

  1. 1つ目の論理グループは、TCPと同様のセマンティクスとなる、SctpChannelSctpServerChannelです。 SctpChannelは、単一のアソシエーション、つまり、単一のエンドポイントに入出力するデータの送受信のみを制御できます。 SctpServerChannelは、そのソケット・アドレス上で開始された新しいアソシエーションをリスニングし、受け入れます。
  2. 2つ目の論理グループはSctpMultiChannelのみで構成されます。 このチャネル・タイプのインスタンスは複数のアソシエーションを制御できます。そのため、異なる複数のエンドポイントに入出力するデータを送受信できます。

SCTPスタックはイベント駆動型であり、アプリケーションは特定のSCTPイベントの通知を受け取ることができます。 これらのイベントは、SctpMultiChannelと使用するともっとも有効です。このクラスは複数のアソシエーションを制御できるので、通知の状況を追跡する必要があります。 たとえば、AssociationChangeNotificationは、新しいアソシエーションの開始または終了を通知します。 アソシエーションが動的なアドレス設定をサポートしている場合、PeerAddressChangeNotificationは、ピア・エンドポイントに追加された、またはピア・エンドポイントから削除されたIPアドレスを通知します。 MessageInfoを使用すると、送信中または受信中のメッセージの補助的なデータを使用できます。

マルチストリーミングの例

次の例では、SCTPのマルチストリーミング機能について示します。 この例のサーバーは、あるタイプの日時プロトコルを実装します。 一方のストリームでは英語(米国)形式、もう一方のストリームではフランス語形式でフォーマットした現在の日時を送信します。

コードを読みやすくするため、エラー処理は省略しています。

多言語日時サーバー(DaytimeServer)

次に、DaytimeServerのソース・コードを示します。

publicclassDaytimeServer{
staticint SERVER_PORT =3456;
staticint US_STREAM =0;
staticint FR_STREAM =1;

staticSimpleDateFormatUSformatter=newSimpleDateFormat(
"h:mm:ss a EEE d MMM yy, zzzz",Locale.US);
staticSimpleDateFormatFRformatter=newSimpleDateFormat(
"h:mm:ss a EEE d MMM yy, zzzz",Locale.FRENCH);

publicstaticvoid main(String[] args)throwsIOException{
SctpServerChannel ssc =SctpServerChannel.open();
InetSocketAddress serverAddr =newInetSocketAddress(SERVER_PORT);
ssc
.bind(serverAddr);

ByteBuffer buf =ByteBuffer.allocateDirect(60);
CharBuffer cbuf =CharBuffer.allocate(60);
Charset charset =Charset.forName("ISO-8859-1");
CharsetEncoder encoder = charset.newEncoder();

while(true){
SctpChannel sc = ssc.accept();

/* get the current date */
Date today =newDate();
cbuf
.put(USformatter.format(today)).flip();
encoder
.encode(cbuf, buf,true);
buf
.flip();

/* send the message on the US stream */
MessageInfo messageInfo =MessageInfo.createOutgoing(null,
US_STREAM
);
sc
.send(buf, messageInfo);

/* update the buffer with French format */
cbuf
.clear();
cbuf
.put(FRformatter.format(today)).flip();
buf
.clear();
encoder
.encode(cbuf, buf,true);
buf
.flip();

/* send the message on the French stream */
messageInfo
.streamNumber(FR_STREAM);
sc
.send(buf, messageInfo);

cbuf
.clear();
buf
.clear();

sc
.close();
}
}
}

多言語日時クライアント(DaytimeClient)

次に、DaytimeClientのソース・コードを示します。

publicclassDaytimeClient{
staticint SERVER_PORT =3456;
staticint US_STREAM =0;
staticint FR_STREAM =1;

publicstaticvoid main(String[] args)throwsIOException{
InetSocketAddress serverAddr =newInetSocketAddress("localhost",
SERVER_PORT
);
ByteBuffer buf =ByteBuffer.allocateDirect(60);
Charset charset =Charset.forName("ISO-8859-1");
CharsetDecoder decoder = charset.newDecoder();

SctpChannel sc =SctpChannel.open(serverAddr,0,0);

/* handler to keep track of association setup and termination */
AssociationHandler assocHandler =newAssociationHandler();

/* expect two messages and two notifications */
MessageInfo messageInfo =null;
do{
messageInfo
= sc.receive(buf,System.out, assocHandler);
buf
.flip();

if(buf.remaining()>0&&
messageInfo
.streamNumber()== US_STREAM){

System.out.println("(US) "+ decoder.decode(buf).toString());
}elseif(buf.remaining()>0&&
messageInfo
.streamNumber()== FR_STREAM){

System.out.println("(FR) "+ decoder.decode(buf).toString());
}
buf
.clear();
}while(messageInfo !=null);

sc
.close();
}

staticclassAssociationHandler
extendsAbstractNotificationHandler
{
publicHandlerResult handleNotification(AssociationChangeNotificationnot,
PrintStream stream){
if(not.event().equals(COMM_UP)){
int outbound =not.association().maxOutboundStreams();
int inbound =not.association().maxInboundStreams();
stream
.printf("New association setup with %d outbound streams"+
", and %d inbound streams.\n", outbound, inbound);
}

returnHandlerResult.CONTINUE;
}

publicHandlerResult handleNotification(ShutdownNotificationnot,
PrintStream stream){
stream
.printf("The association has been shutdown.\n");
returnHandlerResult.RETURN;
}
}
}

出力サンプル

出力例は、次のとおりです。

>: java DaytimeClient
New association setup with32 outbound streams,and32 inbound streams.
(US)4:00:51 PM Fri15May09,BritishSummerTime
(FR)4:00:51 PM ven.15 mai 09,Heure d'ete britannique
The association has been shutdown.

この記事に対するコメントをご投稿ください。また、SCTP開発メーリング・リストまでお気軽にご連絡ください。

著者について

Chris Hegartyは、アイルランドにあるSun Microsystemsのソフトウェア・エンジニアです。 余暇は、スーパーバイクのライディングを楽しんでいます。

AltStyle によって変換されたページ (->オリジナル) /