JavaでのStream Control Transport Protocol(SCTP)のサポートが、JDK 7の機能として承認されました。 APIとリファレンス実装の定義は、OpenJDK SCTPプロジェクトを通して実施されました。 この作業はJDK 7 マイルストーン3に統合されており、将来のすべての拡張で利用できます。
Stream Control Transport Protocol(SCTP)は、信頼性に優れたメッセージ指向のトランスポート・プロトコルであり、UDP(User Datagram Protocol)およびTCP(Transmission Control Protocol)と同じ階層に位置します。 SCTPはセッション指向であり、データを転送する前にエンドポイント間のアソシエーションを確立する必要があります。
SCTPはマルチホーミングを直接サポートしています。つまり、エンドポイントを複数のアドレスで表すことができ、各アドレスをデータの送受信に使用できます。このため、ネットワークの冗長性が確保されます。 2つのエンドポイント間のコネクションは、これらのエンドポイント間のアソシエーションと呼ばれます。 エンドポイントは、アソシエーション設定中にアドレスのリストを交換できます。 1つのアドレスがプライマリ・アドレスとして指定されます。これが、ピア・エンドポイントがデータの送信に使用するデフォルト・アドレスとなります。 あるエンドポイントの特定のセッションでは、アドレス・リスト全体で単一のポート番号が使用されます。
SCTPはメッセージベースです。 I/O処理はメッセージに対して行われ、メッセージ間の境界が維持されます。 各アソシエーションは複数の独立した論理ストリームをサポートできます。 各ストリームは、単一のアソシエーション内部におけるメッセージ・シーケンスを表し、ストリームは互いに独立しています。つまり、ストリーム識別子とシーケンス番号がデータ・パケットに含まれており、ストリームごとにメッセージのシーケンスを設定できます。
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つの論理グループに分類できます。
SctpChannelとSctpServerChannelです。 SctpChannelは、単一のアソシエーション、つまり、単一のエンドポイントに入出力するデータの送受信のみを制御できます。 SctpServerChannelは、そのソケット・アドレス上で開始された新しいアソシエーションをリスニングし、受け入れます。SctpMultiChannelのみで構成されます。 このチャネル・タイプのインスタンスは複数のアソシエーションを制御できます。そのため、異なる複数のエンドポイントに入出力するデータを送受信できます。SCTPスタックはイベント駆動型であり、アプリケーションは特定のSCTPイベントの通知を受け取ることができます。 これらのイベントは、SctpMultiChannelと使用するともっとも有効です。このクラスは複数のアソシエーションを制御できるので、通知の状況を追跡する必要があります。 たとえば、AssociationChangeNotificationは、新しいアソシエーションの開始または終了を通知します。 アソシエーションが動的なアドレス設定をサポートしている場合、PeerAddressChangeNotificationは、ピア・エンドポイントに追加された、またはピア・エンドポイントから削除されたIPアドレスを通知します。 MessageInfoを使用すると、送信中または受信中のメッセージの補助的なデータを使用できます。
次の例では、SCTPのマルチストリーミング機能について示します。 この例のサーバーは、あるタイプの日時プロトコルを実装します。 一方のストリームでは英語(米国)形式、もう一方のストリームではフランス語形式でフォーマットした現在の日時を送信します。
コードを読みやすくするため、エラー処理は省略しています。
次に、DaytimeServerのソース・コードを示します。
public class DaytimeServer {
static int SERVER_PORT = 3456;
static int US_STREAM = 0;
static int FR_STREAM = 1;
static SimpleDateFormat USformatter = new SimpleDateFormat(
"h:mm:ss a EEE d MMM yy, zzzz", Locale.US);
static SimpleDateFormat FRformatter = new SimpleDateFormat(
"h:mm:ss a EEE d MMM yy, zzzz", Locale.FRENCH);
public static void main(String[] args) throws IOException {
SctpServerChannel ssc = SctpServerChannel.open();
InetSocketAddress serverAddr = new InetSocketAddress(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 = new Date();
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のソース・コードを示します。
public class DaytimeClient {
static int SERVER_PORT = 3456;
static int US_STREAM = 0;
static int FR_STREAM = 1;
public static void main(String[] args) throws IOException {
InetSocketAddress serverAddr = new InetSocketAddress("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 = new AssociationHandler();
/* 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());
} else if (buf.remaining() > 0 &&
messageInfo.streamNumber() == FR_STREAM) {
System.out.println("(FR) " + decoder.decode(buf).toString());
}
buf.clear();
} while (messageInfo != null);
sc.close();
}
static class AssociationHandler
extends AbstractNotificationHandler
{
public HandlerResult handleNotification(AssociationChangeNotification not,
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);
}
return HandlerResult.CONTINUE;
}
public HandlerResult handleNotification(ShutdownNotification not,
PrintStream stream) {
stream.printf("The association has been shutdown.\n");
return HandlerResult.RETURN;
}
}
}
出力例は、次のとおりです。
>: java DaytimeClient
New association setup with 32 outbound streams, and 32 inbound streams.
(US) 4:00:51 PM Fri 15 May 09, British Summer Time
(FR) 4:00:51 PM ven. 15 mai 09, Heure d'ete britannique
The association has been shutdown.
この記事に対するコメントをご投稿ください。また、SCTP開発メーリング・リストまでお気軽にご連絡ください。
Chris Hegartyは、アイルランドにあるSun Microsystemsのソフトウェア・エンジニアです。 余暇は、スーパーバイクのライディングを楽しんでいます。
