Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在java nio中创建多个侦听到同一端口的udp客户端?_Java_Io_Udp_Nio - Fatal编程技术网

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

如何在java nio中创建多个侦听到同一端口的udp客户端?,java,io,udp,nio,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.

对于普通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.
但是在nio。如何做到这一点?我试着这样做:

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.

如果确实需要所有客户端处理消息,则需要多播/宽播协议。从这个意义上讲,如前一个问题()所述,NIO2支持多播和宽播,但不使用DatagramChannel类。取而代之的是MultiCastChannel接口(您可以在中找到正式文档,并在中找到示例:)。 关于您的代码,它应该如下所示:

   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
我知道原因

单播只能由一个客户端接收,如果多个客户端侦听同一端口,则只有第一个客户端将接收数据

如果希望多个客户端接收数据,则应使用多播或广播

如果使用广播,数据包应发送到255.255.255:port,以便所有侦听端口的客户端都将接收数据。 客户端绑定地址无法使用localhost或127.0.0.1。您应该使用0.0.0.0或InetSocketAddress(端口)或您的本地地址,如192.168.100.123

如果任何其他应用程序绑定没有“reuseAddress”的端口,那么您也不能绑定该端口

科特林代码:

fun main(args: Array<String>) {
    val selector = Selector.open()
    val reader = DatagramChannel.open()
    val sender = DatagramChannel.open()

    reader.configureBlocking(false)
    reader.socket().reuseAddress = true
//    reader.bind(InetSocketAddress("0.0.0.0", 1234))
//    reader.bind(InetSocketAddress("192.168.100.37", 1234))
    reader.bind(InetSocketAddress(1234))
    reader.register(selector, SelectionKey.OP_READ)

    sender.socket().broadcast = true

    val t = Thread {
        while (true) {
            val line = readLine()
            if (line != null) {
                val buffer = ByteBuffer.wrap(line.toByteArray())
                sender.send(buffer, InetSocketAddress("255.255.255.255", 1234))
            }
        }
    }
    t.isDaemon = true
    t.start()


    while (selector.isOpen) {
        val n = selector.select()
        if (n == 0) continue
        val keys = selector.selectedKeys().iterator()
        while (keys.hasNext()) {
            val key = keys.next()
            keys.remove()
            if (key.isReadable) {
                val buffer = ByteBuffer.allocateDirect(1024)
                val channel = key.channel() as DatagramChannel
                val address = channel.receive(buffer)
                buffer.flip()
                val s = Charsets.UTF_8.decode(buffer)
                println("$address says : $s")
            }
        }
    }
}
fun main(args:Array){
val selector=selector.open()
val reader=DatagramChannel.open()
val sender=DatagramChannel.open()
reader.configureBlocking(错误)
reader.socket().reuseAddress=true
//reader.bind(InetSocketAddress(“0.0.0.0”,1234))
//reader.bind(InetSocketAddress(“192.168.100.37”,1234))
reader.bind(InetSocketAddress(1234))
读卡器.寄存器(选择器,SelectionKey.OP_READ)
sender.socket().broadcast=true
val t=螺纹{
while(true){
val line=readLine()
如果(行!=null){
val buffer=ByteBuffer.wrap(line.toByteArray())
sender.send(缓冲区,InetSocketAddress(“255.255.255.255”,1234))
}
}
}
t、 isDaemon=true
t、 开始()
while(selector.isOpen){
val n=选择器。选择()
如果(n==0)继续
val keys=selector.selectedKeys().iterator()
while(keys.hasNext()){
val key=keys.next()
keys.remove()
如果(键isReadable){
val buffer=ByteBuffer.allocateDirect(1024)
val channel=key.channel()作为DatagramChannel
val地址=通道接收(缓冲区)
buffer.flip()
val s=字符集.UTF_8.解码(缓冲区)
println(“$address表示:$s”)
}
}
}
}

reader2接收0字节。如果我先定义RealRe2,那么RealeR2将接收数据,但是RealRe1接收0字节。@ TyNy请考虑它是否有用。所有客户端都将接收数据。