Как только вы начинаете искать работающий 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, этот случай я разберу в одной из следующих заметок.