简体   繁体   English

多播套接字在无限循环中不断接收相同的消息

[英]Multicastsocket keeps receiving same message in infinite loop

I'm writing a java chat application using Multicast.我正在使用 Multicast 编写一个 java 聊天应用程序。 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());
        }
    }

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一段时间后,我在这里找到了答案: 使用 Ehcache 多播获取`无法分配请求的地址` java.net.SocketException

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 .这感觉好像与IP_MULTICAT_LOOP套接字选项有关,该选项在 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.尝试禁用此套接字选项,看看会发生什么。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM