UDP Multicast с Java: сообщение не может быть получено всей многоадресной группой

Я пытаюсь понять, как работает многоадресная рассылка, поэтому немного экспериментирую с ней.

Ситуация

Я построил простой сервер с MulticastSocket, прослушивающим порт 1250. Он просто повторяет полученное сообщение.

Затем я создал простой клиент, также с MulticastSocket, прослушивающий порт 4711. Он отправляет String-Message на сервер и ждет любого сообщения, которое вернется.

Ожидаемое поведение

Я хочу, чтобы два или более клиентов отправляли свое собственное уникальное сообщение на сервер и получали все ответы, которые сервер отправляет обратно группе многоадресной рассылки, прослушивающей порт 4711.

Наблюдаемое поведение / проблема

Как только я запускаю более одного экземпляра клиента, все ответы от сервера получает только первый клиент, который присоединился к группе. Все остальные клиенты, которые присоединились к группе многоадресной рассылки на порту 4711, ничего не получают. Почему это и как решить проблему?

Результат выглядит следующим образом (вы можете видеть, что только процесс MulticastEchoClient2 получает ответ сервера):

MulticastEchoServerMulticastEchoClient1 MulticastEchoClient2

Код

Серверный код

public class MulticastEchoServer
{
    public static void main(String[] args)
    {
        if (args.length != 2)
        {
            System.out.println("Wrong usage of parameters! <MulticastAddress><id>");
            return;
        }

        UDPMulticastSocket socket = null;
        String id = args[1];

        try
        {
            socket = new UDPMulticastSocket(1250);
            System.out.println("Socket created...");

            socket.join(args[0]);

            while(true)
            {
                String msg = socket.receive(1024);
                System.out.println("Message received: " + msg + " from " + socket.getSenderAddress() + ":" + socket.getSenderPort());

                if (msg.toLowerCase().equals("quit"))
                {
                    System.out.println("Shutting down...");
                    break;
                }

                socket.reply("Reply from " + id + " -> " + msg);
            }

            socket.leave(args[0]);
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }

        if (socket != null)
        {
            socket.close();
            System.out.println("Shutting down...");
        }
    }
}

Код клиента

public class MulticastEchoClient
{
    public final static int MESSAGES = 10000;

    public static void main(String[] args)
    {
        if (args.length != 3)
        {
            System.out.println("Wrong usage of parameters: <Multicast-Address><Address of Server><id>");
            return;
        }

        UDPMulticastSocket socket = null;
        String id = args[2];

        try
        {
            socket = new UDPMulticastSocket(4711);
            socket.setTimeout(1000);
            System.out.println("Socket created...");

            socket.join(args[0]);
            InetAddress srvrAddress = InetAddress.getByName(args[1]);

            for (int i = 0; i < MESSAGES; i++)
            {
                socket.send(id + " sending: " + i, srvrAddress, 1250);

                try
                {
                    while(true)
                    {
                        String msg = socket.receive(1024);
                        System.out.println("Message received: " + msg + " from " + socket.getSenderAddress() + ":" + socket.getSenderPort());
                    }
                }
                catch (IOException e)
                {
                    System.out.println("All messages received...");
                }
            }

            socket.leave(args[0]);
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }

        if (socket != null)
        {
            socket.close();
            System.out.println("Shutting down...");
        }
    }
}

Полезные классы

public class UDPSocket
{
    protected DatagramSocket socket;
    private InetAddress senderAddress;
    private int senderPort;

    //constructors
    protected UDPSocket(DatagramSocket socket)
    {
        this.socket = socket;
    }

    public UDPSocket() throws SocketException
    {
        this(new DatagramSocket());
    }

    public UDPSocket(int port) throws SocketException
    {
        this(new DatagramSocket(port));
    }

    //getters
    public InetAddress getSenderAddress()
    {
        return senderAddress;
    }

    public int getSenderPort()
    {
        return senderPort;
    }

    //setters
    public void setTimeout(int timeout) throws SocketException
    {
        socket.setSoTimeout(timeout);
    }

    //methods
    public void send(String s, InetAddress rcvrAddress, int rcvrPort) throws IOException
    {
        byte[] data = s.getBytes();
        DatagramPacket outPacket = new DatagramPacket(data, 0, data.length, rcvrAddress, rcvrPort);

        socket.send(outPacket);
    }

    public String receive(int maxBytes) throws IOException
    {
        byte[] data = new byte[maxBytes];
        DatagramPacket inPacket = new DatagramPacket(data, 0, data.length);
        socket.receive(inPacket);

        senderAddress = inPacket.getAddress();
        senderPort = inPacket.getPort();

        //return new String(data, 0, data.length);
        return new String(data, 0, inPacket.getLength());
    }

    public void reply(String s) throws IOException
    {
        if (senderAddress != null)
        {
            send(s, senderAddress, senderPort);
        }
        else
        {
            throw new IOException("ERROR: No one to reply to!");
        }
    }

    public void close()
    {
        socket.close();
    }
}

public class UDPMulticastSocket extends UDPSocket
{
    public UDPMulticastSocket(int port) throws IOException
    {
        super(new MulticastSocket(port));
    }

    public UDPMulticastSocket() throws IOException
    {
        super(new MulticastSocket());
    }

    public void join(String mcAddress) throws IOException
    {
        InetAddress ia = InetAddress.getByName(mcAddress);
        ((MulticastSocket) socket).joinGroup(ia);
    }

    public void leave(String mcAddress) throws IOException
    {
        InetAddress ia = InetAddress.getByName(mcAddress);
        ((MulticastSocket) socket).leaveGroup(ia);
    }
}

person Christian    schedule 05.06.2014    source источник
comment
Вы отвечаете на адрес отправителя, поэтому ответ получает только адрес отправителя. Почему ты удивлен? Если вы хотите ответить группе многоадресной рассылки, отвечайте группе многоадресной рассылки, а не адресу отправителя.   -  person user207421    schedule 05.06.2014
comment
В этом случае сообщения от Client1 должны быть возвращены клиенту 1, а сообщения от Client2 должны быть возвращены Client2. Но они ОБЕИ возвращаются ОДНОМУ клиенту. Вы можете это объяснить?   -  person Christian    schedule 05.06.2014
comment
Я не понимаю, о чем вы говорите. Может, ты меня тоже не поняла. Вы отправляете ответ на IP-адрес однорангового узла, отправившего запрос. Вы должны отправить его на IP-адрес многоадресной группы.   -  person user207421    schedule 07.06.2014
comment
Джепп, понял. Работает сейчас! Спасибо. Если вы не против опубликовать свое решение в качестве ответа, я был бы рад поставить ему +1 и проверить его как правильный ответ!   -  person Christian    schedule 07.06.2014


Ответы (1)


Вы отвечаете на адрес отправителя, поэтому ответ получает только адрес отправителя. Если вы хотите ответить группе многоадресной рассылки, отвечайте группе многоадресной рассылки, а не адресу отправителя.

person user207421    schedule 09.06.2014