Продвинутые SCTP клиент и сервер

Протокол SCTP является очень перспективным и предоставляет множество интересных возможностей. В данной заметке я рассмотрю использование продвинутых SCTP клиента и сервера из примеров netty (простые клиент и сервер рассмотрены тут: Простые SCTP клиент и сервер ). Проект будет на maven. Скорее всего с ходу вам скомпилировать примеры из репозитория (репозиторий) не удастся. Я перечислю еще раз все установки и изменения, после которых пример должен заработать (возможно некоторые шаги не обязательны). Исключение вида java.lang.UnsupportedOperationException: libsctp.so.1: cannot open shared object file: No such file or directory лечится установкой библиотеки:
yum install lksctp-tools
Исключения java.net.SocketException: Permission denied при запуске лечатся установкой переменной окружения:
export _JAVA_OPTIONS="-Djava.net.preferIPv4Stack=true"
и/или отключением SELinux ( https://bugs.openjdk.java.net/browse/JDK-7045222 ) - у меня установлен CentOS :
echo 0 > /selinux/enforce
Исключения вида com.sun.nio.sctp. UnsupportedOperatingSystemException.raise (UnsupportedOperatingSystemException.java:20 означают, что для запуска использована не та java. Нужна java из JDK, она подхватывает необходимые классы из com.sun.nio.sctp.*. Без этих зависимостей я собрать не мог:
    <dependency>
	<groupId>io.netty</groupId>
	<artifactId>netty-all</artifactId>
	<version>5.0.0.Alpha1</version>
    </dependency>
 
    <dependency>
	<groupId>org.jboss.errai.io.netty</groupId>
	<artifactId>netty-transport-sctp</artifactId>
	<version>4.0.0.Alpha1.errai.r1</version>
    </dependency>
Клиент и сервер из примеров занимаются пересылкой друг другу одной и той же строки. Я изменил эту логику: клиент присылает строку, сервер делает квитирование. При этом строки извлечены из SCTP сообщения в буфер и готовы для дальнейшей обработки (у меня они просто выводятся в стандартный поток). Таким образом, изменения коснулись только хендлеров. Я не буду приводить весь исходный код и загромождать статью. Приведу только измененные места ( исходники можно скачать тут: sctp_advanced). Класс SctpEchoClientHandler. В конструкторе урезал размер буфера и пишу в него только читаемые символы.
    public SctpEchoClientHandler() {
        firstMessage = Unpooled.buffer(SctpEchoClient.SIZE);
        for (int i = 49; i < 127/*firstMessage.capacity()*/; i++) {
            firstMessage.writeByte((byte) i);
        }
    }
А тут сделано эхоподавление 🙂 (оно просто закомментировано). Клиент выводит в поток ответ сервера на принятое сообщение (можно поместить содержимое буфера в строку и передать на дальнейшую обработку):
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
 
    	// got response from server, preparing String representation
    	SctpMessage sm = (SctpMessage) msg;
    	ByteBuf buffer = sm.content(); //
 
    	System.out.println("Response from server received: ");
 
    	for (int i = 0; i < buffer.capacity(); i ++) {
    		byte b = buffer.getByte(i);
    		System.out.print((char) b);
    	}
    	System.out.println("");
 
    	//***********************************
        //ctx.write(msg); // echoing
    }
Класс SctpEchoServerHandler. Добавлена строка с подтверждением:
	private static final String SERVER_RESPONSE = "Acquittance from server";
В конструкторе заполняем буфер, который понадобится при каждом ответе:
    public SctpEchoServerHandler() {
        byte[] bytes = SERVER_RESPONSE.getBytes( Charset.forName("UTF-8" ));
 
        response = Unpooled.buffer(SctpEchoClient.SIZE);
        for (int i = 0; i < bytes.length; i++) {
            response.writeByte(bytes[i]);
        }
    }
Опять подавляем эхо, пишем клиентское сообщение в поток, посылаем квмтанцию:
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
 
    	// got response from server, preparing String representation
    	SctpMessage sm = (SctpMessage) msg;
    	ByteBuf buffer = sm.content();
 
    	System.out.println("Message from client received: ");
 
    	for (int i = 0; i < buffer.capacity(); i ++) {
    		byte b = buffer.getByte(i);
    		System.out.print((char) b);
    	}
    	System.out.println("");
    	//***********************************
        //ctx.write(msg); // echoing
 
    	ctx.write(new SctpMessage(0, 0, response));
    }
Сначала запускаем сервер:
/usr/java/jdk1.8.0_31/bin/java -cp .:sctp.jar ru.outofrange.sctp.SctpEchoServer
Обратите внимание: нужна java из JDK. Порт сервера 8007, хардкодный. Сервер не прекращает работу после приема одного сообщения. Теперь запускаем клиент:
/usr/java/jdk1.8.0_31/bin/java -cp .:sctp.jar ru.outofrange.sctp.SctpEchoClient
Клиент посылает свой кадр. Сервер рапортует этот же кадр, затем строковое представление:
sctp1
После этого посылает квитирование в кадре. Клиент принимает его, рапортует и выводит свое логгирование:
sctp2
[sc:social_networks ]
You can leave a response, or trackback from your own site.

Leave a Reply