I have multiple servers on my network that all send out a broadcast message. With the following client I am trying to capture all the broadcast messages from all servers. The sending part works fine(not included in this post), but my receiving part doesn't work... I keep getting "SocketException: Not a multicast address", what am I doing wrong?
public static String[] capture(int port) { // port is always 63332
ArrayList<String> clients = new ArrayList<>();
InetAddress address = Utilities.getBroadcastAddress(); // I get "/192.168.2.255" here
MulticastSocket socket = null;
try {
socket = new MulticastSocket(port);
socket.setSoTimeout(2000);
socket.joinGroup(address); // this part throws the exception
DatagramPacket packet;
byte[] packetContent;
while (true) {
packetContent = new byte[1024];
packet = new DatagramPacket(packetContent, packetContent.length);
try {
socket.receive(packet);
String client = packet.getAddress() + ":" + packet.getPort();
clients.add(client);
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
if(socket != null) {
try {
socket.leaveGroup(address);
} catch(IOException e) {
e.printStackTrace();
}
socket.close();
}
return clients.toArray(new String[clients.size()]);
}
You are confusing broadcasting with multicasting. A multicast address is not a broadcast address. Make up your mind which it is that you're doing. If you're receiving multicasts, you need to join the correct multicast address, whatever it is. If you're receiving broadcasts, don't join anything.
Related
Intro
There are a number of tutorials on creating a multicast publisher and receiver.
I used the one found here with a few modifications.
A few others:
here
here
here
note that these tutorials are all quite similar.
Details:
The server runs on port 7777 and sends datagrams to 224.0.0.0 (I tested a couple of other ip's in the multicast range: 224.0.0.0 to 239.255.255.255, but these didn't work)
Client then joins the multicast group 224.0.0.0 and waits for a packet response (run as a thread)
extra: I send a message like: 123.23.13.12[host-name]:1234 as the datagram data.
Problem:
Multicast packets from server (on localhost) not reaching client (on localhost).
Clients include a java console application (code found below) and Android application on Android Emulator. Both clients do not receive multicast packets.
I know that the multicast packets are being sent as this is shown in Wireshark
Below you will find a basic example of that which I have.
TL;DR: Server sends multicast packets (confirmed via Wireshark) but client doesn't receive them.
Suggestions are very welcome!
UPDATE
Based on Just another Java programmer's comment, I check my firewall. Lo and behold, my firewall was dropping on the input and forward chains. I set this to acceptall incoming (temporarily)
Based on Ron Maupin's comments.
I have changed the message sent to exclude the hostname, thus the message sent is 123.12.13.23:1234
I have changed the multicast send address to 239.254.0.0 which is within the specified range (see Ron's comment)
the multicast port is set to 7777
the outgoing interface is set with s.setInterface(InetAddress.getLocalHost()) in the broadcastServer() try catch block
With these changes applied, the client(s) still do not receive any packets.
Code:
Server Side (Console App):
String multicastAddress = "239.254.0.0", multicastPort = 7777;
private void broadcastServer() {
String message = null;
MulticastSocket s = null;
InetAddress local = null, group = null;
InetAddress[] allByName;
try {
local = InetAddress.getLocalHost();
s = new MulticastSocket(multicastPort);
s.setReuseAddress(true);
s.setInterface(local)
s.joinGroup(InetAddress.getByName(multicastAddress));
group = InetAddress.getByName(multicastAddress);
} catch (SocketException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
MulticastSocket socket = s;
// getNetworkIP() gets lan network ip
// serverport = 1025
message = local.getHostAddress() + ":" + String.valueOf(serverPort);
byte[] buf = message.getBytes();
DatagramPacket packet = new DatagramPacket(buf, buf.length, group, multicastPort);
thdBroadcaster = new Thread(() -> {
while (bRunServer) {
try {
Thread.sleep(1000);
printf("[Broadcast] Broadcasting...");
socket.send(packet);
printf("OK\n");
printf("");
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
socket.close();
});
thdBroadcaster.start();
}
Client Side (Console app):
String multicastAddress = "239.254.0.0", multicastPort = 7777;
private void startServerListenerThread() {
Thread thdServerListener = new Thread(new Runnable() {
#Override
public void run() {
MulticastSocket socket = null;
InetAddress group = null;
try {
socket = new MulticastSocket(multicastPort);
socket.setReuseAddress(true);
group = InetAddress.getByName(multicastAddress);
socket.joinGroup(group);
handleServerBroadcasts(socket);
socket.leaveGroup(group);
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private void handleServerBroadcasts(final MulticastSocket socket) {
while (true){
try {
byte[] buf = new byte[256];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
String received = new String(packet.getData());
String address = received.substring(0, received.indexOf(":"));
String port = received.substring(received.indexOf(":") + 1);
System.out.println();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception x){
x.printStackTrace();
}
}
}
});
thdServerListener.start();
}
You are calling setReuseAddress() after binding the socket. It has no effect. You need to create an unbound MulticastSocket, call setReuseAddress(), and then bind it.
The solution ended up being a trivial change.
Resolving the issue was as simple as changing:
s = new MulticastSocket(multicastPort);
to
s = new MulticastSocket();
on the server side ONLY
Note: The firewall is a requirement, check if multicast packets are allowed through. The interface I used is localhost, not a requirement though. However this can be set by getting the specified interface you need.
UPDATE
EJP's comment:
I changed the port used to 8888. This port was used to send server datagrams and for the client to connect on with their MulticastSocket
I'm developing a simple UDP communication software to communicate with my robot.
I've been able to use this code to send the first packet but when I try to send the second it does not send neither does it give me errors, what did I do wrong?
EDIT : The problem is I can't use the send void twice.
Code :
Send Void:
public static void Send(String Message)
{
Client Clt = new Client();
Clt.Message = Message;
Clt.start();
}
Client :
public class Client extends Thread {
public String Message;
public void run()
{
PrintStream myPS = null;
try {
myPS = new PrintStream(Start.CltSkt.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
myPS.println(Message);
try {
finalize();
} catch (Throwable e) {
e.printStackTrace();
}
}
}
EDIT 2 (Problem Solved) :
thanks to everyone that answered/commented the questions especially to EJP.
The problem was :
I was not using a DatagramSocket so I ended up with this :
public static void Send(String Message)
{
InetAddress Ip = null;
DatagramSocket datagramSocket = null;
try {
datagramSocket = new DatagramSocket();
} catch (SocketException ex) {
Logger.getLogger(Start.class.getName()).log(Level.SEVERE, null, ex);
}
byte[] buffer = Message.getBytes();
DatagramPacket packet;
try {
Ip = InetAddress.getByName(CltIp);
} catch (UnknownHostException ex) {
Logger.getLogger(Start.class.getName()).log(Level.SEVERE, null, ex);
}
packet = new DatagramPacket(buffer, buffer.length, Ip, Integer.parseInt(CltPort));
try {
datagramSocket.send(packet);
} catch (IOException ex) {
Logger.getLogger(Start.class.getName()).log(Level.SEVERE, null, ex);
}
}
I was not awere of the the use with datagram sockets! Now I'm :)
I've been sending packets to clients connected to the server fine, but trying to
send the same packet to the actual host itself keeps coming up with an error.
Here is the code that breaks
if(socket == null)
{
try
{
socket = new DatagramSocket( port );
}
catch (SocketException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if( server.returnPlayers() > 0)
{
byte[] buf = new byte[256];
DatagramPacket packet = new DatagramPacket( buf, buf.length );
try
{
socket.receive( packet ); ..<---this line
}
catch (IOException e)
{
Log.d(TAG, "Error with receiving data");
e.printStackTrace();
}
...
Any idea why? the same packet is sent to the clients, and it works 100%.
Canvas
Your try/catch is too local It is possible for 'socket' to be still null after the catch. Move the catch to the end of this code. Don't catch exceptions until after the code that can be affected by them.
I am trying to send packets from one host to another peer host using java UDP protocol.
The one host sends data, while the other reads it. The corresponding read however keeps blocking, thus receiving no data. I can see the sender packets going to the right destination using wireshark, but the receiver just wont pick it up. The read operation keeps blocking indefinitely.
Please help.
Code for cient:
//CLIENT CLASS
//Sections ommited....
DatagramSocket so = new DatagramSocket(port);
protected void send(byte[] buffer,int packetsize){
DatagramPacket p;
try {
myClient.notifyInform("Sending data to "+inetaddress+" on"+port+"\n");
p=new DatagramPacket(buffer,buffer.length,InetAddress.getByName(inetaddress),port);
writeLock.lock();
try{
so.send(p);
}finally{
writeLock.unlock();
}
} catch (UnknownHostException e) {
myClient.perror("Could not connect to peer:"+e.getMessage()+"\n");
e.printStackTrace();
} catch (IOException e) {
myClient.perror("IOException while sending to peer.\n");
e.printStackTrace();
}
}
protected DatagramPacket read(){
byte[] buf=new byte[bufsize];
DatagramPacket p=new DatagramPacket(buf,buf.length);//TODO check these values, what should buffer be? just made it psize*10 for now
readLock.lock();
try{
myClient.notifyInform("receiving data\n");
so.receive(p);
this.myclient.notifyInform(String.valueOf(p.getData().length)+"\n");
} catch (IOException e) {
myClient.perror("IOException while reading from peer.\n");
e.printStackTrace();
}finally{
readLock.unlock();
}
return p;
}
protected void beginRead() {
while(active) {
System.out.println("########################");
byte[] data=this.read().getData();
myClient.notifyInform("Receiving data\n");
}
}
protected void beginSend(){
forkWork(new Runnable(){
#Override
public void run() {
byte[] sendBuffer=new byte[bufsize];
int cnt;
while(callActive){
try{
sourceLock.lock();
cnt=dataSource.read(sendBuffer, 0, bufsize);
}finally{
sourceLock.unlock();
}
if (cnt >0) {
send(sendBuffer, packetsize);
}
}
}
});
}
UPDATE:I made a mistake that I finally tracked down. After binding the port, and fixing that error, it now works.
You need to specify the port that the datagram socket is listening on like this:
this.so = new DatagramSocket(SOME_NUMBER_HERE);
and make sure you send it to the same port number in the send() method
Is your receiving DatagramSocket listening at the IP:port the sender is sending to?
This code works perfectly in Ubuntu, Windows, and Mac OS X. It also works fine with a Nexus One running Android 2.1.1.
I start sending and listening multicast datagrams, and all the computers and the Nexus One will see each other perfectly. Then I run the same code on a Droid (Firmware 2.0.1), and everybody will get the packets sent by the Droid, but the droid will listen only to its own packets.
This is the run() method of a thread that's constantly listening on a Multicast group for incoming packets sent to that group.
I'm running my tests on a local network where I have multicast support enabled in the router.
My goal is to have devices meet each other as they come online by broadcasting packages to a multicast group.
public void run() {
byte[] buffer = new byte[65535];
DatagramPacket dp = new DatagramPacket(buffer, buffer.length);
try {
MulticastSocket ms = new MulticastSocket(_port);
ms.setNetworkInterface(_ni); //non loopback network interface passed
ms.joinGroup(_ia); //the multicast address, currently 224.0.1.16
Log.v(TAG,"Joined Group " + _ia);
while (true) {
ms.receive(dp);
String s = new String(dp.getData(),0,dp.getLength());
Log.v(TAG,"Received Package on "+ _ni.getName() +": " + s);
Message m = new Message();
Bundle b = new Bundle();
b.putString("event", "Listener ("+_ni.getName()+"): \"" + s + "\"");
m.setData(b);
dispatchMessage(m); //send to ui thread
}
} catch (SocketException se) {
System.err.println(se);
} catch (IOException ie) {
System.err.println(ie);
}
}
This is the code that sends the Multicast Datagram out of every valid network interface available (that's not the loopback interface).
public void sendPing() {
MulticastSocket ms = null;
try {
ms = new MulticastSocket(_port);
ms.setTimeToLive(TTL_GLOBAL);
List<NetworkInterface> interfaces = getMulticastNonLoopbackNetworkInterfaces();
for (NetworkInterface iface : interfaces) {
//skip loopback
if (iface.getName().equals("lo"))
continue;
ms.setNetworkInterface(iface);
_buffer = ("FW-"+ _name +" PING ("+iface.getName()+":"+iface.getInetAddresses().nextElement()+")").getBytes();
DatagramPacket dp = new DatagramPacket(_buffer, _buffer.length,_ia,_port);
ms.send(dp);
Log.v(TAG,"Announcer: Sent packet - " + new String(_buffer) + " from " + iface.getDisplayName());
}
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e2) {
e2.printStackTrace();
}
}
Update (April 2nd 2010)
I found a way to have the Droid's network interface to communicate using Multicast: WifiManager.MulticastLock.
MulticastLock _wifiMulticastLock = ((WifiManager) context.getSystemService(Context.WIFI_SERVICE)).createMulticastLock("multicastLockNameHere");
_wifiMulticastLock.acquire();
Then when you're done...
if (_wifiMulticastLock != null && _wifiMulticastLock.isHeld())
_wifiMulticastLock.release();
After I did this, the Droid started sending and receiving UDP Datagrams on a Multicast group.
Update Jul-6-2010
Per request, here's my current code, the next method exists on an abstract class that can be used for both Broadcast and Multicast receivers.
public void run() {
onInit();
try {
byte[] data = new byte[65535];
while (isProcessing()) {
try {
DatagramPacket receivedDatagram = new DatagramPacket(data, data.length);
_socket.receive(receivedDatagram);
onDatagramReceived(receivedDatagram);
data = new byte[65535]; // This pattern is for saving memory allocation.
} catch (InterruptedIOException e) {
if (!isProcessing())
break;
}
} // while
} catch (Exception e) {
Log.e(TAG, e.getMessage(), e);
} finally {
onStop();
_socket.close();
_socket.disconnect();
}
}
Your extending classes should implement onInit() and onDatagramReceived()
For a Multicast receiver, onInit() looks something like this:
_socket = new MulticastSocket(PORT_MULTICAST);
InetAddress groupAddress = InetAddress.getByAddress(MULTICAST_GROUP_ADDRESS);
InetAddress groupInetAddress = FrostWireUtils.fastResolveAddress(groupAddress); //reflection hack to not resolve ips
try {
_socket.setSoTimeout(500);
_socket.setTimeToLive(MULTICAST_TTL_GLOBAL);
_socket.setReuseAddress(true);
_socket.setNetworkInterface(
WifiUtils.getWifiNetworkInterface());
_socket.joinGroup(groupInetAddress);
WifiUtils.lockMulticast();
} catch (Exception e) {
Log.e(TAG, e.getMessage(), e);
}
I've implemented another test, this time using UDP Broadcast.
It works.
Conclusion: To the extent of my knowledge Motorola Droid phones on firmware 2.0.1 don't support multicast, but you can always use regular DatagramPackets on the broadcast address.