java - 如何在java nio中创建多个监听同一端口的udp客户端?

标签 java io udp nio

对于普通的io,我可以这样做:

s1=new DatagramSocket(1234)
s2=new DatagramSocket(1234)

bytes=xxxxxx
packet = DatagramPacket(bytes, bytes.size,InetSocketAddress("localhost",1234))
new DatagramSocket().send(packet)
//  and then the s1 and s2 can receive the packet.

但在蔚来。这个怎么做?我尝试过这样的:

第一:

s1=DatagramChannel.open()
s1.bind(new Inetsocketaddress("localhost",1234)

s2=DatagramChannel.open()
s2.bind(new Inetsocketaddress("localhost",1234)// will throw an exception

第二个:

s1=DatagramChannel.open()
s1.setOption(StandardSocketOptions.SO_REUSEADDR, true);
s1.bind(new Inetsocketaddress("localhost",1234)

s2=DatagramChannel.open()
s2.setOption(StandardSocketOptions.SO_REUSEADDR, true);
s2.bind(new Inetsocketaddress("localhost",1234)

//these code will not throw exception. but s2 cannot receive any data.
// when i close s1,  then s2 will receive data.

最佳答案

如果您确实需要所有客户端都处理消息,则需要多播/广播协议(protocol)。从这个意义上说,正如上一个问题( Does Java NIO support broadcast or multicast? )中所述,NIO2 支持多播和广播,但不使用 DatagramChannel 类。相反,您拥有 MultiCastChannel 接口(interface)(您可以在 http://javanio.info/filearea/nioserver/WhatsNewNIO2.pdf 中找到官方文档,并在 How do I implement a multicast client in NIO.2? 中找到示例)。 关于您的代码,它应该如下所示:

   NetworkInterface netInterface = NetworkInterface.getByName("em1");
   InetAddress group = InetAddress.getByName("localhost");

   // Reader 1
   System.out.println("Create Reader 1");
   DatagramChannel s1 = DatagramChannel.open(StandardProtocolFamily.INET);
   s1.setOption(StandardSocketOptions.SO_REUSEADDR, true);
   s1.bind(new InetSocketAddress(PORT));
   s1.setOption(StandardSocketOptions.IP_MULTICAST_IF, netInterface);

   // Reader 2
   System.out.println("Create Reader 2");
   DatagramChannel s2 = DatagramChannel.open(StandardProtocolFamily.INET);
   s2.setOption(StandardSocketOptions.SO_REUSEADDR, true);
   s2.bind(new InetSocketAddress(PORT));
   s2.setOption(StandardSocketOptions.IP_MULTICAST_IF, netInterface);

请注意,您的底层硬件堆栈必须支持多播/广播。否则,join 方法将抛出异常。

如果您不需要所有客户端都处理该消息,而是需要其中任何客户端处理该消息而不阻塞其他客户端,则可以设置非阻塞套接字选项。考虑到您提供的代码,我在下面添加了一个非阻塞的解决方案:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.charset.StandardCharsets;


public class Main {

    private static final String HOST = "localhost";
    private static final int PORT = 1234;

    private static final String MESSAGE = "HelloWorld";
    private static final int MESSAGE_SIZE = MESSAGE.length();


    public static void main(String[] args) throws IOException {
        // Reader 1
        System.out.println("Create Reader 1");
        DatagramChannel s1 = DatagramChannel.open();
        s1.configureBlocking(false);
        s1.setOption(StandardSocketOptions.SO_REUSEADDR, true);
        s1.bind(new InetSocketAddress(HOST, PORT));

        // Reader 2
        System.out.println("Create Reader 2");
        DatagramChannel s2 = DatagramChannel.open();
        s2.configureBlocking(false);
        s2.setOption(StandardSocketOptions.SO_REUSEADDR, true);
        s2.bind(new InetSocketAddress(HOST, PORT));

        // Writer
        System.out.println("Create Writer");
        DatagramChannel s3 = DatagramChannel.open();

        // Send and receive messages
        System.out.println("Send message");
        send(s3);
        System.out.println("Receive message on Reader 1");
        receive(s1);
        System.out.println("Receive message on Reader 2");
        receive(s2);

        // Close
        System.out.println("Close");
        s1.close();
        s2.close();
        s3.close();
    }

    private static void send(DatagramChannel channel) throws IOException {
        ByteBuffer buf = ByteBuffer.allocate(MESSAGE_SIZE);
        buf.clear();
        buf.put(MESSAGE.getBytes());
        buf.flip();

        int bytesSent = channel.send(buf, new InetSocketAddress(HOST, PORT));
        System.out.println("Sent: " + bytesSent);
    }

    private static void receive(DatagramChannel channel) throws IOException {
        ByteBuffer buf = ByteBuffer.allocate(MESSAGE_SIZE);
        buf.clear();

        channel.receive(buf);

        String str = new String(buf.array(), StandardCharsets.UTF_8);
        System.out.println("Received: " + str);
    }

}

输出是:

Create Reader 1
Create Reader 2
Create Writer
Send message
Sent: 10
Receive message on Reader 1
Received: 
Receive message on Reader 2
Received: HelloWorld
Close

关于java - 如何在java nio中创建多个监听同一端口的udp客户端?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44922595/

相关文章:

java - GWT Cookies,在 rpc 期间设置时返回 null

Java 8 vs Python 2.7 pbkdf2 哈希 - 不同的输出哈希字母大小写

java - 为什么在应该返回简短工作的方法中返回 int?

C++ fstream,从文本中读取数据并执行数学运算?

c++ - 通过 Indy UDP 正确发送和接收结构

android - MulticastSocket保持监听功能

java - JAX-WS:为什么嵌套元素位于 ""命名空间中?

c++ - 尝试使用带有 C++ 的 MoveFile 移动文件时出现 ERROR_INVALID_NAME

c - 来自用户输入的动态指针数组

Java UDP发送/接收小例子不起作用