I try to implement a UDP client server detection via broadcast. The idea is the following: I have a server, which is bound to port 12344 and a client which is bound to port 12345. Now, the client sends a broadcast package to 255.255.255.255 12344. The server should reply to this package with a other package to IPClient:12345.
The implementation uses Java nio.
The problem is, that on windows, the server gets the packages but cannot(?) send an answer (I don't see the answer in wireshark).
I have the following example code:
Client
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();
}
}
Server example
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);
The problem is here. You can't connect to the broadcast address, and in any case it doesn't make sense. The broadcast address isn't sending to you, you are sending to it. The server is sending to you from its own bind-address. Just remove this line. You will have to use DatagramChannel.send() rather than write(), as you are unconnected.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With