我正在以非阻塞模式使用连接的DatagramChannel来接收UDP多播。我发现DatagramChannel.read(ByteBuffer)
每当我的程序收到空的UDP多播消息时都返回 -1 。但是API文档说:“ 读取的字节数,可能为零,或者如果通道已到达流末尾,则为-1 ”。
我希望流结束是无法再使用该通道的条件-就像封闭的TCP连接一样,但是完全有可能继续使用DatagramChannel用于 -1 之后接收。
可以安全地假设即使read(ByteBuffer)
返回 -1 之后,仍然可以继续使用DatagramChannel吗?
当接收到一个空的UDP消息时,有一个返回值指示流结束的返回值对有点有点奇怪吗?如果返回值为 0 会更合适吗?
这是我的测试程序,首先是多播发射机:
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.SocketAddress;
import java.net.StandardProtocolFamily;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
public class LocalServer {
final static int PORT = 7001;
final static String MCAST_ADDRESS = "233.2.3.3";
final static String INTERFACE_ADDRESS = "127.0.0.1";
public static void main(String[] args) throws IOException {
NetworkInterface ni = NetworkInterface.getByInetAddress(InetAddress.getByName(INTERFACE_ADDRESS));
System.out.println("ChannelServer: ni=" + ni.getDisplayName());
DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET).setOption(StandardSocketOptions.SO_REUSEADDR, true).bind(
new InetSocketAddress(PORT)).setOption(StandardSocketOptions.IP_MULTICAST_IF, ni);
InetAddress group = InetAddress.getByName(MCAST_ADDRESS);
SocketAddress dst = new InetSocketAddress(group, PORT);
int i = 0;
while (true) {
System.out.println("Transmitting #" + i);
ByteBuffer asterixBuf = ByteBuffer.wrap(
("line " + i + "123456789012345678901234567890123456789012345678901234567890").getBytes());
dc.send(asterixBuf, dst);
i++;
// Randomly transmit an empty UDP datagram and then sleep.
if (Math.random() > 0.50d) {
System.out.println("Transmitting an empty buffer");
ByteBuffer emptyBuf = ByteBuffer.allocate(0);
dc.send(emptyBuf, dst);
try {
Thread.sleep(300);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
然后是多播接收器:
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.StandardProtocolFamily;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.MembershipKey;
public class LocalClient {
final static int PORT = LocalServer.PORT;
final static String MCAST_ADDRESS = LocalServer.MCAST_ADDRESS;
final static String CONNECT_HOST = LocalServer.INTERFACE_ADDRESS;
final static String INTERFACE_ADDRESS = CONNECT_HOST;
public static void main(String[] args) throws IOException {
NetworkInterface ni = NetworkInterface.getByInetAddress(InetAddress.getByName(INTERFACE_ADDRESS));
System.out.println("ChannelClient: ni=" + ni.getDisplayName());
DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET).setOption(StandardSocketOptions.SO_REUSEADDR, true).bind(
new InetSocketAddress(PORT)).setOption(StandardSocketOptions.IP_MULTICAST_IF, ni);
InetAddress group = InetAddress.getByName(MCAST_ADDRESS);
MembershipKey key = dc.join(group, ni);
dc.configureBlocking(false);
InetSocketAddress foreignInetAddress = new InetSocketAddress(InetAddress.getByName(CONNECT_HOST), 0);
dc.connect(foreignInetAddress);
ByteBuffer receiveBuffer = ByteBuffer.allocate(64 * 1024);
while (true) {
dc.receive(receiveBuffer);
int bytesRead = dc.read(receiveBuffer);
if (bytesRead == -1) {
System.out.println("bytesRead=" + bytesRead);
}
else if (bytesRead > 0) {
receiveBuffer.flip();
System.out.println();
while (receiveBuffer.hasRemaining())
System.out.print((char) receiveBuffer.get());
System.out.println();
receiveBuffer.clear();
try {
Thread.sleep(100);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}