SCTP

SCTP en JAVA

API

SCTP n'est pas implémenté dans la version officielle du JDK actuel (1.6), mais une implémentation est proposée dans le JDK 1.7.

Les objets SCTP utilisés dans les classes ci-dessous viennent du package : com.sun.nio.sctp.

Pour le client et le serveur, le code est relativement similaire à une implémentation en TCP, seule l'utilisation de l'objet MessageInfo est nouvelle. Cet objet permet de fixer ou de récupérer différentes informations comme :

Pour le moment l'implémentation de SCTP dans le JDK 1.7 n'est pas complè. En effet, le multi-homing ne semble pas fonctionnel : après la coupure de l'interface réseau utilisée l'application nous n'avons pas observé de basculement de la communication sur notre seconde interface...

Client

Le client consiste à saisir des messages au clavier, les encoder et les envoyer au serveur sur un stream différent à chaque fois.

Voici sa classe :

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.util.Scanner;


import com.sun.nio.sctp.MessageInfo;
import com.sun.nio.sctp.SctpChannel;

public class Client {
	private SctpChannel sc;
	private final static int BUFFER_SIZE = 1024;
	private final static int SERVER_PORT = 1111;

	public Client(String addr, int port) throws IOException { 
		this.sc = SctpChannel.open(new InetSocketAddress(addr, port), 0, 0);
	}

	public void start() throws IOException {
		MessageInfo messageInfo = MessageInfo.createOutgoing(null, 0);
		Charset charset = Charset.forName("ISO-8859-1");
		CharsetEncoder encoder = charset.newEncoder();

		ByteBuffer buf = ByteBuffer.allocate(BUFFER_SIZE);
		CharBuffer cbuf = CharBuffer.allocate(BUFFER_SIZE);

		Scanner scan = new Scanner(System.in);
		
		int i =0;
		int max = this.sc.association().maxInboundStreams();
		
		//messageInfo.unordered(true);
		
		while (scan.hasNext()) {
			buf.clear();
			cbuf.clear();
			
			cbuf.put(scan.nextLine());
			cbuf.flip();
			
			encoder.encode(cbuf, buf, true);
			buf.flip();

			messageInfo.streamNumber(i%max);
			this.sc.send(buf, messageInfo);

			i++;					
		}
	}
	
	public void stop() throws IOException{
		this.sc.close();
	}

	public static void main(String[] args) {
		try {
			Client client = new Client("127.0.0.1", SERVER_PORT);
			//Client client = new Client("192.168.0.1", SERVER_PORT);
			
			client.start();
			client.stop();
		} catch (IOException e) {
			System.out.println("Error : " + e.getMessage());
		}

	}

}

			

Serveur

Le serveur récupère les messages, les décode puis affiche leur contenu et leur stream.

Voici sa classe :

import java.io.IOException;
import java.io.PrintStream;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.Iterator;


import com.sun.nio.sctp.AbstractNotificationHandler;
import com.sun.nio.sctp.AssociationChangeNotification;
import com.sun.nio.sctp.AssociationChangeNotification.AssocChangeEvent;
import com.sun.nio.sctp.HandlerResult;
import com.sun.nio.sctp.MessageInfo;
import com.sun.nio.sctp.SctpChannel;
import com.sun.nio.sctp.SctpServerChannel;
import com.sun.nio.sctp.ShutdownNotification;

public class Server {
	private final static int SERVER_PORT = 1111;
	private final static int BUFFER_SIZE = 1024;

	private SctpServerChannel ssc;

	public Server(int port) throws IOException {
		this.ssc = SctpServerChannel.open();
		this.ssc.bind(new InetSocketAddress(port));
		
		System.out.println("SCTP server started.");
		System.out.println("Local addresses :");
		Iterator iterator = this.ssc.getAllLocalAddresses().iterator();
		while(iterator.hasNext()){
			System.out.println(iterator.next());
		}
	}

	public void launch() throws IOException {
		ByteBuffer buf = ByteBuffer.allocate(BUFFER_SIZE);
		CharBuffer cbuf = CharBuffer.allocate(BUFFER_SIZE);

		Charset charset = Charset.forName("ISO-8859-1");
		CharsetDecoder decoder = charset.newDecoder();
		
		
		while (true) {
			System.out.println("Waiting for client connection...");
			
			SctpChannel sc = this.ssc.accept();
			
			System.out.println("Client connected");
			System.out.println("Remote adresses :");
			Iterator iterator = sc.getRemoteAddresses().iterator();
			while(iterator.hasNext()){
				System.out.println(iterator.next());
			}
			
			AssociationHandler assocHandler = new AssociationHandler();
			MessageInfo messageInfo = null;
			
			do {
				buf.clear();
				cbuf.clear();
				
				
				messageInfo = sc.receive(buf, null, assocHandler);								
				buf.flip();

				messageInfo.unordered(true);
				if (messageInfo != null && buf.limit() > 0) {
					decoder.decode(buf, cbuf, true);
					cbuf.flip();

					System.out.print("Stream("+messageInfo.streamNumber()+"):");
					System.out.println(cbuf);
				}

			} while (messageInfo != null && buf.limit() > 0);
			System.out.println("Connection closed by peer.");
		}
	}

	public static void main(String[] args) {
		try {
			Server server = new Server(SERVER_PORT);
			server.launch();
		} catch (IOException e) {
			System.out.println("Error : " + e.getMessage());
		}
	}

	static class AssociationHandler extends AbstractNotificationHandler {
		
		public HandlerResult handleNotification(
				AssociationChangeNotification not, PrintStream stream) {
			if (not.event().equals(AssocChangeEvent.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;
		}
	}
}