Как только вы начинаете искать работающий java код для этих классов, то получаете в выдаче устаревшие примеры (сомневаюсь, что они работали уже на момент публикации).
В этой заметке я разберу пример простых клиента и сервера для протокола SCTP и типовые ошибки при сборке и запуске.
Исключение вида
java.lang.UnsupportedOperationException: libsctp.so.1: cannot open shared object file: No such file or directory лечится установкой библиотеки:
Исключения
java.net.SocketException: Permission denied при запуске лечатся установкой переменной окружения:
export _JAVA_OPTIONS="-Djava.net.preferIPv4Stack=true" |
export _JAVA_OPTIONS="-Djava.net.preferIPv4Stack=true"
и/или отключением SELinux (
https://bugs.openjdk.java.net/browse/JDK-7045222 ) - у меня установлен CentOS :
echo 0 > /selinux/enforce |
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> |
<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 |
/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]));
}
} |
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();
}
} |
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 |
[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 |
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, этот случай я разберу в одной из следующих заметок.
[sc:social_networks ]