Я использую подключенный DatagramChannel в неблокирующем режиме для получения многоадресной рассылки UDP.Я обнаружил, что DatagramChannel.read(ByteBuffer)
возвращает -1 всякий раз, когда моя программа получает пустое многоадресное UDP-сообщение.Но документация API гласит: « Количество прочитанных байтов, возможно, ноль или -1, если канал достиг конца потока ».
Я ожидал бы end-of-stream , чтобы быть условием, при котором канал больше не может использоваться - точно так же как закрытое TCP-соединение, но вполне возможно продолжать использовать DatagramChannel для приема после получения -1 .
Можно ли предположить, что всегда можно продолжать использовать DatagramChannel даже после того, как read(ByteBuffer)
вернул -1 ?
Это маленький странно иметь возвращаемое значение, указывающее конец потока когда все, что произошло, - это получение пустого UDP-сообщения?Не было бы более уместно, если бы возвращаемое значение было 0 ?
Вот мои тестовые программы, сначала многоадресный передатчик:
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.SocketAddress;
import java.net.StandardProtocolFamily;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
public class LocalServer {
final static int PORT = 7001;
final static String MCAST_ADDRESS = "233.2.3.3";
final static String INTERFACE_ADDRESS = "127.0.0.1";
public static void main(String[] args) throws IOException {
NetworkInterface ni = NetworkInterface.getByInetAddress(InetAddress.getByName(INTERFACE_ADDRESS));
System.out.println("ChannelServer: ni=" + ni.getDisplayName());
DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET).setOption(StandardSocketOptions.SO_REUSEADDR, true).bind(
new InetSocketAddress(PORT)).setOption(StandardSocketOptions.IP_MULTICAST_IF, ni);
InetAddress group = InetAddress.getByName(MCAST_ADDRESS);
SocketAddress dst = new InetSocketAddress(group, PORT);
int i = 0;
while (true) {
System.out.println("Transmitting #" + i);
ByteBuffer asterixBuf = ByteBuffer.wrap(
("line " + i + "123456789012345678901234567890123456789012345678901234567890").getBytes());
dc.send(asterixBuf, dst);
i++;
// Randomly transmit an empty UDP datagram and then sleep.
if (Math.random() > 0.50d) {
System.out.println("Transmitting an empty buffer");
ByteBuffer emptyBuf = ByteBuffer.allocate(0);
dc.send(emptyBuf, dst);
try {
Thread.sleep(300);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
А затем многоадресная передачаполучатель:
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.StandardProtocolFamily;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.MembershipKey;
public class LocalClient {
final static int PORT = LocalServer.PORT;
final static String MCAST_ADDRESS = LocalServer.MCAST_ADDRESS;
final static String CONNECT_HOST = LocalServer.INTERFACE_ADDRESS;
final static String INTERFACE_ADDRESS = CONNECT_HOST;
public static void main(String[] args) throws IOException {
NetworkInterface ni = NetworkInterface.getByInetAddress(InetAddress.getByName(INTERFACE_ADDRESS));
System.out.println("ChannelClient: ni=" + ni.getDisplayName());
DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET).setOption(StandardSocketOptions.SO_REUSEADDR, true).bind(
new InetSocketAddress(PORT)).setOption(StandardSocketOptions.IP_MULTICAST_IF, ni);
InetAddress group = InetAddress.getByName(MCAST_ADDRESS);
MembershipKey key = dc.join(group, ni);
dc.configureBlocking(false);
InetSocketAddress foreignInetAddress = new InetSocketAddress(InetAddress.getByName(CONNECT_HOST), 0);
dc.connect(foreignInetAddress);
ByteBuffer receiveBuffer = ByteBuffer.allocate(64 * 1024);
while (true) {
dc.receive(receiveBuffer);
int bytesRead = dc.read(receiveBuffer);
if (bytesRead == -1) {
System.out.println("bytesRead=" + bytesRead);
}
else if (bytesRead > 0) {
receiveBuffer.flip();
System.out.println();
while (receiveBuffer.hasRemaining())
System.out.print((char) receiveBuffer.get());
System.out.println();
receiveBuffer.clear();
try {
Thread.sleep(100);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}