0

I'm writing a java chat application using Multicast. The clients can communicate among themselves but they can also send predefined messages to the server who always has the same answer to the respective predefined message.

Both client and server can receive and send messages. They are both subscribing recipients to the same host and port, so their sockets are the same, but when a client is sending a predefined message to the server, the server gets stuck in an infinite loop receiving the same message.

Code Server

       final Lock lock = new ReentrantLock();
       final Condition Rx  = lock.newCondition(); 
       final Condition Tx = lock.newCondition(); 
       private volatile boolean msgRead;
       private volatile int TypeMsg;

       try{
            NetworkInterface nif = NetworkInterface.getByName("en1");
            MSocket = new MulticastSocket(port_chat);
            group = InetAddress.getByName(adresse_chat);
            MSocket.joinGroup(new InetSocketAddress(adresse_chat, port_chat), nif);
        }catch(IOException se){
            System.out.println(this.toString() + " IOException -> " + se.getMessage());
        }

       /*
            Thread Rx
        */

        new Thread(){
            @Override
            public void run(){
                while(!isInterrupted()){
                    lock.lock();
                    try{
                        while(msgRead == true)
                            Rx.await();
                        byte[] buf = new byte[256];
                        DatagramPacket packetRx = new DatagramPacket(buf, buf.length);
                        try{
                            MSocket.receive(packetRx);
                        }catch(IOException ioe){
                            System.out.println(this.toString() + " IOException -> " + ioe.getMessage());
                        }

                        String received = new String(packetRx.getData(), 0, packetRx.getLength());
                        if("end".equals(received))
                            break;

                        if(received.contains("WEATHER_FORECAST") == true)
                            TypeMsg = 1;
                        else
                            if(received.contains("ASK_AGE_CAPTAIN") == true)
                                TypeMsg = 2;

                        msgRead = true;
                        Tx.signal();
                    }catch(InterruptedException ie){
                        System.out.println("Thread Rx -> " + ie.getMessage());
                    }
                    finally{
                        lock.unlock();
                    }
                }
            }
        }.start();

        /*
            Thread Tx
        */

        new Thread(){
            @Override
            public void run(){
                while(!isInterrupted()){
                    lock.lock();
                    try{
                        while(msgRead == false)
                            Tx.await();

                        byte[] buf = new byte[256];

                        /* switch(TypeMsg){...} */

                        buf = text.getBytes();
                        DatagramPacket packetTx = new DatagramPacket(buf, buf.length, group, port_chat);

                        try{
                            MSocket.send(packetTx);
                        }catch(IOException ioe){
                            System.out.println(this.toString() + " IOException -> " + ioe.getMessage());
                        }
                        msgRead = false;
                        Rx.signal();
                    }catch(InterruptedException ie){
                        System.out.println("Thread Tx -> " + ie.getMessage());
                    }finally{
                        lock.unlock();
                    }
                }
            }
        }.start();

Code Client

     try{
            NetworkInterface nif = NetworkInterface.getByName("en1");
            MSocket = new MulticastSocket(port_chat);
            group = InetAddress.getByName(adresse_chat);
            MSocket.joinGroup(new InetSocketAddress(adresse_chat, port_chat), nif);
        }catch(IOException se){
            System.out.println(this.toString() + " IOException -> " + se.getMessage());
        }

/*  
    Thread Rx
*/
new Thread(){
            @Override
            public void run(){
                while(!isInterrupted()){
                    byte[] buf = new byte[256];
                    DatagramPacket packetRx = new DatagramPacket(buf, buf.length);
                    try{
                        MSocket.receive(packetRx);
                    }catch(IOException ioe){
                        System.out.println(this.toString() + " IOException -> " + ioe.getMessage());
                    }

                    String received = new String(packetRx.getData(), 0, packetRx.getLength());
                    if("end".equals(received))
                        break;

                    jTextArea_Rx.append(received + "\n");
                }
            }
        }.start();

/*
  Tx
*/
private void jButton_SendActionPerformed(java.awt.event.ActionEvent evt) {                                             
        byte[] buf = new byte[256];
        String text = username + " >> " + jTextArea_Tx.getText();
        buf = text.getBytes();

        DatagramPacket packetTx = new DatagramPacket(buf, buf.length, group, port_chat);

        try{
            MSocket.send(packetTx);
        }catch(IOException ioe){
            System.out.println(this.toString() + " IOException -> " + ioe.getMessage());
        }
    }
Daniel B
  • 91
  • 1
  • 5

2 Answers2

0

I got it, I had to add

System.setProperty("java.net.preferIPv4Stack", "true");

at the beginning of the application and I also changed this part

try{
        NetworkInterface nif = NetworkInterface.getByName("en1");
        MSocket = new MulticastSocket(port_chat);
        group = InetAddress.getByName(adresse_chat);
        MSocket.joinGroup(new InetSocketAddress(adresse_chat, port_chat), nif);
    }catch(IOException se){
        System.out.println(this.toString() + " IOException -> " + se.getMessage());
    }

to

try{
        MSocket = new MulticastSocket(port_chat);
        group = InetAddress.getByName(adresse_chat);
        MSocket.joinGroup(group);
    }catch(IOException se){
        System.out.println(this.toString() + " IOException -> " + se.getMessage());
    }

so no need to explicitly specifying the interface. I found the answer after some time here: Getting `Can't assign requested address` java.net.SocketException using Ehcache multicast

Daniel B
  • 91
  • 1
  • 5
  • You should definitely be specifying the interface. That was incorrect to remove that part. If you don't specify it, then you defer to the OS which interface it will actually use which can change between executions depending on how you configure things at the OS level. – searchengine27 Aug 12 '21 at 14:44
0

This feels like it has something to do with the IP_MULTICAT_LOOP socket option which is surprisingly enabled by default in Java Multicast Sockets. Basically when this flag is enabled, you will receive messages you send on the multicast socket. So if you also send a message when you receive a message and you have this enabled, then you can create a loop.

Try disabling this socket option and see what happens.

Liam Kelly
  • 3,524
  • 1
  • 17
  • 41