DatagramChannel.read () возвращает -1 при получении пустой многоадресной рассылки UDP - PullRequest
0 голосов
/ 24 ноября 2018

Я использую подключенный 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();
                }
            }
        }
    }
}
...