Простые SCTP клиент и сервер на java

Как только вы начинаете искать работающий java код для этих классов, то получаете в выдаче устаревшие примеры (сомневаюсь, что они работали уже на момент публикации).
В этой заметке я разберу пример простых клиента и сервера для протокола SCTP и типовые ошибки при сборке и запуске.

Исключение вида 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.*.

Я собирал проект под maven и для избавления от предупреждения о неудовлетворенных импортах классов использовал зависимость:

        <dependency>
		<groupId>org.jboss.errai.io.netty</groupId>
		<artifactId>netty-transport-sctp</artifactId>
		<version>4.0.0.Alpha1.errai.r1</version>
	</dependency>

Эта зависимость мне была нужна даже при указании эклипсу использовать джаву из jdk:

/home/dk/Downloads/eclipse/eclipse -vm /usr/java/jdk1.8.0_31/bin/java

В моем SCTP сервере обработка происходит в бесконечном цикле и выводится каждое принятое сообщение в строковом представлении. Подтверждение со стороны сервера или какой-то ответ клиенту не реализованы.

Код сервера:

package ru.outofrange.sctp;
 
import java.io.*;
import java.net.*;
 
import com.sun.nio.sctp.*;
 
import java.nio.*;
 
public class SctpServer 
{
	public static final int MESSAGE_SIZE = 1000;
 
	public void go(int port)
	{
		//Buffer to hold messages in byte format
		ByteBuffer byteBuffer = ByteBuffer.allocate(MESSAGE_SIZE);
		String message;
		try
		{
			//Open a server channel
			SctpServerChannel sctpServerChannel = SctpServerChannel.open();
			//Create a socket address in the current machine at port
			InetSocketAddress serverAddr = new InetSocketAddress(port);
			//Bind the channel's socket to the server in the current machine at port
			sctpServerChannel.bind(serverAddr);
			//Server goes into a permanent loop accepting connections from clients	
			System.out.println("Waiting for messages ...");
			while(true)
			{
				//Listen for a connection to be made to this socket and accept it
				//The method blocks until a connection is made
				//Returns a new SCTPChannel between the server and client
				SctpChannel sctpChannel = sctpServerChannel.accept();
				//Receive message in the channel (byte format) and store it in buf
				//Note: Actual message is in byte format stored in buf
				//MessageInfo has additional details of the message
				byteBuffer = ByteBuffer.allocate(MESSAGE_SIZE);
				MessageInfo messageInfo = sctpChannel.receive(byteBuffer,null,null);
				//Just seeing what gets stored in messageInfo
				System.out.println(messageInfo);
				//Converting bytes to string. This looks nastier than in TCP
				//So better use a function call to write once and forget it :)
 
				message = byteToString(byteBuffer);
				//Finally the actual message
				System.out.println(message);
 
			}
 
		}
		catch(IOException ex)
		{
			ex.printStackTrace();
		}
	}
 
	public String byteToString(ByteBuffer byteBuffer)
	{
		byteBuffer.position(0);
		byteBuffer.limit(MESSAGE_SIZE);
		byte[] bufArr = new byte[byteBuffer.remaining()];
		byteBuffer.get(bufArr);
		return new String(bufArr);
	}
 
	public static void main(String args[])
	{
 
		SctpServer SctpServerObj = new SctpServer();
		SctpServerObj.go(Integer.valueOf(args[0]));
	}
 
}

Клиент посылает строку вида «Hello from client » + случайное число — так в логе сервера можно проверять, что получаем именно то, что отправлено из клиента (а не застарелую строку из буфера). После отправки единственной строки происходит выход из клиента.

Код клиента:

package ru.outofrange.sctp;
 
import java.io.*;
import java.net.*;
 
import com.sun.nio.sctp.*;
 
import java.nio.*;
import java.util.Random;
 
public class SctpClient 
{
	public static final int MESSAGE_SIZE = 100;
	private int port;
 
	public SctpClient(int port){
		this.port = port;
	}
 
	public void go()
	{
		//Buffer to hold messages in byte format
		ByteBuffer byteBuffer = ByteBuffer.allocate(MESSAGE_SIZE);
 
		Random rand = new Random();
		String message = "Hello from client " + String.valueOf(rand.nextInt(50));
		try
		{
			//Create a socket address for server at net01 at port
			SocketAddress serverSocketAddress = new InetSocketAddress("localhost", port);
 
			//Open a channel.
			SctpChannel sctpChannel = SctpChannel.open();
 
			//Connect the channel's socket to  the remote server
			sctpChannel.connect(serverSocketAddress);
			//Before sending messages add additional information about the message
			Association assoc = sctpChannel.association();
 
			MessageInfo messageInfo = MessageInfo.createOutgoing(assoc, serverSocketAddress, 0);
			//convert the string message into bytes and put it in the byte buffer
			byteBuffer.put(message.getBytes());
			//Reset a pointer to point to the start of buffer 
			byteBuffer.flip();
			//Send a message in the channel (byte format)
			sctpChannel.send(byteBuffer, messageInfo);
			System.out.println("Message sent: " + message);
 
		}
		catch(IOException ex)
		{
			ex.printStackTrace();
		}
	}
	public static void main(String args[])
	{
		// expecting server port in the first command line argument - args[0]
		// server host name is hard coded so far - "localhost" 
		SctpClient SctpClientObj = new SctpClient(Integer.valueOf(args[0]));
		SctpClientObj.go();
	}
}

Пример запуска клиента:

[root@dmitry dk]# /usr/java/latest/bin/java -cp .:sctp1.jar ru.outofrange.sctp.SctpClient 8007
Message sent: Hello from client 11
[root@dmitry dk]# /usr/java/latest/bin/java -cp .:sctp1.jar ru.outofrange.sctp.SctpClient 8007
Message sent: Hello from client 4
[root@dmitry dk]# /usr/java/latest/bin/java -cp .:sctp1.jar ru.outofrange.sctp.SctpClient 8007
Message sent: Hello from client 15
[root@dmitry dk]# /usr/java/latest/bin/java -cp .:sctp1.jar ru.outofrange.sctp.SctpClient 8007
Message sent: Hello from client 49

Соответствующий лог сервера:

sun.nio.ch.sctp.MessageInfoImpl@1540e19d[Address: /127.0.0.1:34052, Association: sun.nio.ch.sctp.AssociationImpl@677327b6[associationID:301, maxIn:10, maxOut:10], Assoc ID: 301, Bytes: 20, Stream Number: 0, Complete: true, isUnordered: false]
Hello from client 11
sun.nio.ch.sctp.MessageInfoImpl@14ae5a5[Address: /127.0.0.1:59299, Association: sun.nio.ch.sctp.AssociationImpl@7f31245a[associationID:303, maxIn:10, maxOut:10], Assoc ID: 303, Bytes: 19, Stream Number: 0, Complete: true, isUnordered: false]
Hello from client 4
sun.nio.ch.sctp.MessageInfoImpl@6d6f6e28[Address: /127.0.0.1:41714, Association: sun.nio.ch.sctp.AssociationImpl@135fbaa4[associationID:305, maxIn:10, maxOut:10], Assoc ID: 305, Bytes: 20, Stream Number: 0, Complete: true, isUnordered: false]
Hello from client 15
sun.nio.ch.sctp.MessageInfoImpl@45ee12a7[Address: /127.0.0.1:55108, Association: sun.nio.ch.sctp.AssociationImpl@330bedb4[associationID:307, maxIn:10, maxOut:10], Assoc ID: 307, Bytes: 20, Stream Number: 0, Complete: true, isUnordered: false]
Hello from client 49

Ни в клиенте, ни в сервере не используется netty, этот случай я разберу в одной из следующих заметок.

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

Leave a Reply