- 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
- Data partitioned into multiple streams
- Independent sequenced delivery
- Eliminates head-of-line blocking
Support for SCTP in JDK 7
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 are 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
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
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
Following is an example of the output you might get:
>: 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.