Продвинутые 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

You can leave a response, or trackback from your own site.

Leave a Reply