Java nio udp广播

标签 java udp nio

我尝试通过广播实现 UDP 客户端服务器检测。想法如下:我有一个绑定(bind)到端口 12344 的服务器和一个绑定(bind)到端口 12345 的客户端。现在,客户端发送一个广播包到 255.255.255.255 12344。服务器应该回复这个包其他包到 IPClient:12345。

实现使用Java nio。

问题是,在 Windows 上,服务器获取包但不能(?)发送答案(我在 wireshark 中看不到答案)。

我有以下示例代码:

客户端

public final class ASyncUDPClient {
public static void main(String[] args) throws IOException {
  InetSocketAddress hostAddress = new InetSocketAddress("255.255.255.255", 12344);
  System.out.println(hostAddress);

  // Create a non-blocking socket channel
  DatagramChannel channel = DatagramChannel.open();
  channel.socket().setBroadcast(true);
  channel.socket().bind(new InetSocketAddress(getAddress(), 12345));
  channel.configureBlocking(false);

  // Kick off connection establishment
  channel.connect(hostAddress);

  ByteBuffer buffer = getBuffer();

  Selector selector = Selector.open();
  channel.write(buffer);
  System.out.println("data send");
  channel.register(selector, SelectionKey.OP_READ);

  while (true) {
    final int select = selector.select();
    System.out.println("select " + select);
    Iterator selectedKeys = selector.selectedKeys().iterator();
    while (selectedKeys.hasNext()) {
      System.out.println("key selected");
      SelectionKey key = (SelectionKey) selectedKeys.next();
      selectedKeys.remove();

      if (!key.isValid()) {
        continue;
      }

      if (key.isReadable()) {
        System.out.println("read");
      } else if (key.isWritable()) {
        System.out.println("write");
      }
    }
  }
}

private static ByteBuffer getBuffer() throws CharacterCodingException {
  return Charset.forName("UTF-8").newEncoder().encode(CharBuffer.wrap("1234"));
}

private static InetAddress getAddress() throws SocketException {
  final Enumeration<NetworkInterface> networkInterfaces =   NetworkInterface.getNetworkInterfaces();
  NetworkInterface networkInterfaceToUse = null;
  while (networkInterfaces.hasMoreElements()) {
    final NetworkInterface networkInterface = networkInterfaces.nextElement();
    if (networkInterface.getDisplayName().contains("Virtual")) continue;
    if (networkInterface.isVirtual()) continue;
    if (networkInterface.isLoopback()) continue;
    if (!networkInterface.isUp()) continue;
    networkInterfaceToUse = networkInterface;
    System.out.println(networkInterfaceToUse);
  }
  return networkInterfaceToUse.getInterfaceAddresses().get(1).getAddress();
}

}

服务器示例

public class ASyncUDPSvr {

static int BUF_SZ = 1024;
static int port = 12344;

static public void main(String[] args) {
  ASyncUDPSvr svr = new ASyncUDPSvr();
  svr.process();
}

private static InetAddress getAddress() throws SocketException {
  final Enumeration<NetworkInterface> networkInterfaces =    NetworkInterface.getNetworkInterfaces();
  NetworkInterface networkInterfaceToUse = null;
  while (networkInterfaces.hasMoreElements()) {
    final NetworkInterface networkInterface = networkInterfaces.nextElement();
    if (networkInterface.getDisplayName().contains("Virtual")) continue;
    if (networkInterface.isVirtual()) continue;
    if (networkInterface.isLoopback()) continue;
    if (!networkInterface.isUp()) continue;
    networkInterfaceToUse = networkInterface;
    System.out.println(networkInterfaceToUse);
  }
  return networkInterfaceToUse.getInterfaceAddresses().get(1).getAddress();
}

private void process() {
  try {
    Selector selector = Selector.open();
    DatagramChannel channel = DatagramChannel.open();
    InetSocketAddress isa = new InetSocketAddress(getAddress(), port);
    channel.socket().bind(isa);
    channel.configureBlocking(false);
    SelectionKey clientKey = channel.register(selector, SelectionKey.OP_READ);
    clientKey.attach(new Con());
    while (true) {
      try {
        selector.select();
        Iterator selectedKeys = selector.selectedKeys().iterator();
        while (selectedKeys.hasNext()) {
          try {
            SelectionKey key = (SelectionKey) selectedKeys.next();
            selectedKeys.remove();
            if (!key.isValid()) {
              continue;
            }
            if (key.isReadable()) {
              read(key);
              key.interestOps(SelectionKey.OP_WRITE);
            } else if (key.isWritable()) {
              write(key);
              key.interestOps(SelectionKey.OP_READ);
            }
          } catch (IOException e) {
            System.err.println("glitch, continuing... " + (e.getMessage() != null ? e.getMessage() : ""));
          }
        }
      } catch (IOException e) {
        System.err.println("glitch, continuing... " + (e.getMessage() != null ? e.getMessage() : ""));
      }
    }
  } catch (IOException e) {
    System.err.println("network error: " + (e.getMessage() != null ? e.getMessage() : ""));
  }
}

private void read(SelectionKey key) throws IOException {
  DatagramChannel chan = (DatagramChannel) key.channel();
  Con con = (Con) key.attachment();
  con.sa = chan.receive(con.req);
  System.out.println("sender address: " + con.sa + "rcv: " + new   String(con.req.array(), "UTF-8"));
  con.resp = Charset.forName("UTF-8").newEncoder().encode(CharBuffer.wrap("send string"));
}

private void write(SelectionKey key) throws IOException {
  DatagramChannel chan = (DatagramChannel) key.channel();
  Con con = (Con) key.attachment();
  System.out.println("sending data: " + new String(con.resp.array(), "UTF-8") + " to "   + con.sa);
  chan.send(con.resp, con.sa);
  System.out.println("data send");
}

class Con {

  ByteBuffer req;
  ByteBuffer resp;
  SocketAddress sa;

  public Con() {
    req = ByteBuffer.allocate(BUF_SZ);
  }
}
}

最佳答案

InetSocketAddress hostAddress = new InetSocketAddress("255.255.255.255", 12344);
// ...
channel.connect(hostAddress);

问题就在这里。您无法连接到广播地址,无论如何它都没有意义。广播地址不是发送给你,而是你发送给它。服务器从它自己的绑定(bind)地址发送给你。只需删除此行。您将不得不使用 DatagramChannel.send() 而不是 write(),因为您未连接。

关于Java nio udp广播,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17472781/

相关文章:

c - 如何发送大于系统缓冲区的UDP数据报?

java - 我可以简化从二进制数据中读取简短内容吗

java - 将阻塞 Socket 对象转换为 SocketChannel 的套接字?

java - 突然出现此错误 java.lang.IllegalStateException : Request cannot be executed; I/O reactor status: STOPPED

java - 在 JPA 中使用继承来实现数据类型目的

java - Servlet 资源不可用 HTTP 404

java - 使用 Scanner 时出现 ArrayList IndexOutOfBoundsException

ios - iOS 上的 UDP 广播/设备发现?

java - 可扩展且高性能的消息 channel

java - 如果源包含 Elastic Search Server 中给定的搜索文本,则获取所有文档