java.nio.channels.Selector.select() returns 0 立即
java.nio.channels.Selector.select() returns 0 immediately
以下代码打开 UDP 套接字、设置多播、发送消息并启动读取循环。它使用 Selector.select() 超时读取。
int TIMEOUT = 10000;
String id = "8154@Think420";
try {
NetworkInterface iface = NetworkInterface.getByInetAddress(InetAddress.getByName(address));
try (DatagramChannel channel = DatagramChannel.open(StandardProtocolFamily.INET).setOption(StandardSocketOptions.SO_REUSEADDR, true)) {
channel.socket().bind(new InetSocketAddress(PORT));
channel.setOption(StandardSocketOptions.IP_MULTICAST_IF, iface);
channel.configureBlocking(false);
InetAddress group = InetAddress.getByName("225.4.5.6");
MembershipKey key = channel.join(group, iface);
InetSocketAddress mcast = new InetSocketAddress(key.group(), PORT);
channel.send(ByteBuffer.wrap(id.getBytes()), mcast);
Selector selector = Selector.open();
channel.register(selector, SelectionKey.OP_READ);
ByteBuffer buffer = ByteBuffer.allocate(4096);
while (key.isValid()) {
if (selector.select(TIMEOUT) == 0) {
System.err.println("timeout");
continue;
}
buffer.clear();
InetSocketAddress address = (InetSocketAddress) channel.receive(buffer);
buffer.flip();
String message = Charset.forName("ASCII").decode(buffer).toString();
System.err.format("From %s received: %s\n", address.getHostString(), message);
}
} catch(IOException e) {
e.printStackTrace();
}
} catch(UnknownHostException | SocketException e) {
throw new IllegalArgumentException(e);
}
当我 运行 应用程序的第一个实例时,它工作正常:从它自己接收一条消息,然后循环打印 "timeout"。
这是一个示例输出:
From 127.0.0.1 received: 8154@Think420
timeout
timeout
timeout
当我 运行 另一个实例时出现问题。这个正常工作,但第一个实例立即开始报告超时,大量输出。这里的预期行为是,当第二个实例启动时,第一个和第二个都会收到一条消息,然后每十秒报告一次超时。我做错了什么?
在selector.select()
returns之后,选中的key必须清空,所以修改后的循环体变成
if (selector.select(TIMEOUT) == 0) {
System.err.println("timeout");
continue;
}
buffer.clear();
InetSocketAddress address = (InetSocketAddress) channel.receive(buffer);
buffer.flip();
String message = Charset.forName("ASCII").decode(buffer).toString();
System.err.format("From %s received: %s\n", address.getHostString(), message);
selector.selectedKeys().clear()
有关详细信息,请参阅 Why the key should be removed in `selector.selectedKeys().iterator()` in java nio?。
以下代码打开 UDP 套接字、设置多播、发送消息并启动读取循环。它使用 Selector.select() 超时读取。
int TIMEOUT = 10000;
String id = "8154@Think420";
try {
NetworkInterface iface = NetworkInterface.getByInetAddress(InetAddress.getByName(address));
try (DatagramChannel channel = DatagramChannel.open(StandardProtocolFamily.INET).setOption(StandardSocketOptions.SO_REUSEADDR, true)) {
channel.socket().bind(new InetSocketAddress(PORT));
channel.setOption(StandardSocketOptions.IP_MULTICAST_IF, iface);
channel.configureBlocking(false);
InetAddress group = InetAddress.getByName("225.4.5.6");
MembershipKey key = channel.join(group, iface);
InetSocketAddress mcast = new InetSocketAddress(key.group(), PORT);
channel.send(ByteBuffer.wrap(id.getBytes()), mcast);
Selector selector = Selector.open();
channel.register(selector, SelectionKey.OP_READ);
ByteBuffer buffer = ByteBuffer.allocate(4096);
while (key.isValid()) {
if (selector.select(TIMEOUT) == 0) {
System.err.println("timeout");
continue;
}
buffer.clear();
InetSocketAddress address = (InetSocketAddress) channel.receive(buffer);
buffer.flip();
String message = Charset.forName("ASCII").decode(buffer).toString();
System.err.format("From %s received: %s\n", address.getHostString(), message);
}
} catch(IOException e) {
e.printStackTrace();
}
} catch(UnknownHostException | SocketException e) {
throw new IllegalArgumentException(e);
}
当我 运行 应用程序的第一个实例时,它工作正常:从它自己接收一条消息,然后循环打印 "timeout"。
这是一个示例输出:
From 127.0.0.1 received: 8154@Think420
timeout
timeout
timeout
当我 运行 另一个实例时出现问题。这个正常工作,但第一个实例立即开始报告超时,大量输出。这里的预期行为是,当第二个实例启动时,第一个和第二个都会收到一条消息,然后每十秒报告一次超时。我做错了什么?
在selector.select()
returns之后,选中的key必须清空,所以修改后的循环体变成
if (selector.select(TIMEOUT) == 0) {
System.err.println("timeout");
continue;
}
buffer.clear();
InetSocketAddress address = (InetSocketAddress) channel.receive(buffer);
buffer.flip();
String message = Charset.forName("ASCII").decode(buffer).toString();
System.err.format("From %s received: %s\n", address.getHostString(), message);
selector.selectedKeys().clear()
有关详细信息,请参阅 Why the key should be removed in `selector.selectedKeys().iterator()` in java nio?。