Providing support for Stream Control Transport Protocol (SCTP) in
Java has been approved as one of the features
for JDK7, and the work of defining the API and reference
implementation was done through the SCTP
OpenJDK project. This work was integrated into JDK7
Milestone 3 and is
available in all future promotions.
Brief Introduction to SCTP
The Stream Control Transport Protocol (SCTP) is a reliable,
message-oriented, transport protocol existing at an equivalent level
with UDP (User Datagram Protocol) and TCP (Transmission Control
Protocol). SCTP is session oriented and an association between the
endpoints must be established before any data can be transmitted.
SCTP has direct support for multi-homing, meaning that
an endpoint may be represented by more than one address and each
address may be used for sending and receiving data, thus providing
network redundancy. The connection between two endpoints is referred
to as an association between those endpoints. Endpoints can exchange
a list of addresses during association setup. One address is
designated as the primary address, this is the default address that
the peer will use for sending data. A single port number is used
across the entire address list at an endpoint for a specific session.
SCTP is message based. I/O operations operate upon messages and
message boundaries are preserved. Each association may support
multiple independent logical streams.
Each stream represents a sequence of messages within a single
association and streams are independent
of one another, meaning that stream identifiers and sequence numbers
are included in the data packet to allow sequencing of messages on a
per-stream basis.
Key Features of SCTP
Message framing
Reliable transport service
Session-oriented
Ordered and unordered message
delivery
Multi-Homing
Association between exactly two
endpoints
Each endpoint may be represented
by multiple IP addresses
Provides failover and redundancy
Multi-Streaming
Eliminates head-of-line blocking
Support for SCTP in JDK7
The Java API is based on the NIO
channels framework so that application requiring SCTP can take
advantage of non-blocking multiplexed I/O. A new package
com.sun.nio.sctp
was defined to hold the new classes/interfaces. The package name is com.sun.nio.sctp
rather than something like java.nio.channels.sctp. This distinction means that the API and
implementation are fully supported and publicly accessible, but not part of the
Java SE platform. Once there is more experience in the industry with SCTP then a
standard API can be defined. The main classes
within this package are the three new channel types. These new
channels can be split
into two logical groups.
The first logical group has similar semantics to TCP,
SctpChannel and SctpServerChannel. An
SctpChannel can control only a single association, that
is, sending and receiving data to and from a single endpoint.
SctpServerChannel listens and accepts new associations
initiated on its socket address.
The second logical group consists of
just SctpMultiChannel. Instances of this channel type
can control multiple associations, therefore can send and receive
data to and from many different endpoints.
The SCTP stack is event driven and applications can receive
notifications of certain SCTP events. These events are most useful
with SctpMultiChannel, since it can control multiple
associations you need to track the status of these notifications. For
example, AssociationChangeNotification lets you know
when new associations are started or terminated.
If the association supports dynamic address configuration then
PeerAddressChangeNotification lets you know about IP
addresses that have been added or removed from the peer endpoint.
MessageInfo allows you to provide ancillary data for the
message either being sent or received.
Multi-Streaming Example
This example demonstrates the multi-streaming feature of SCTP. The
server implements a type of daytime protocol. It sends the current
time date formatted in US English on one stream and in French on
another.
Error handling is omitted to make the code more readable.
Multilingual DayTime Server The source for
DaytimeServer can be obtained
here
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();
}
}
}
|
Multilingual DayTime Client The source for
DaytimeClient can be obtained
here
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<PrintStream>
{
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;
}
}
}
|
Sample Output:
>: 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.
As well as posting comments or feedback on this blog please feel free to
mail the sctp development
mailing list.