MulticastSocket.setInterface in multi interface machine - how to use? - java

I have a machine with two network interface cards. I was wondering if I want to send out a multicast message to one of the LANs - is it mandatory to use the machine's ip in that LAN, or can have as input ant ip from the LAN?
That is, let's say the machine's IP is:
190.20.20.20
and another machine in that LAN is:
190.20.20.1
can I put:
multcastiScoket.setInterface("190.20.20.1");
If so - does that machine have to be on turned on?
Thank you.

While multicast has its own routing pecularities, it is important to understand that an explicit choice of the NIC (for both sender and receiver) is important and does make a difference (unless you want to rely on a particular OS'es "automagic" implementations, which can get very tricky in production).
Firstly, let us clarify, that java.net.MulticastSocket can and is used for both: sending and receiving messages (this does not mean that sending MC, and receiving MC are similar; a receiver must perform IGMP joins etc, is visible on ip maddr etc. etc.).
In general, the more you specify while creating these sockets the better (or else you will be at the mercy of the OS, with not-so-easy to debug situations bound to happen).
For the Receiver socket you should:
specify the port (in constructor); firewall should be open for inbound udp traffic on that port,
specify the interface (via socket.setNetworkInterface); else OS will take one of the available interfaces (check via ip maddr),
specify the MC-group (e.g via socket.joinGroup(InetAddress.getByName("230.0.0.0")) (this triggers the IGMP mechanism, visible via tcpdump -i your_interface -n ether multicast)
For the Sender socket you should similarly,
specify the MC group (same command),
specify the interface (same command)
I'd put two arguments if favor of the above,
Tested simple senders and receivers on CentOS 7 with two NIC's (enp0s3, and enp0s8) (code here). Only by setting NIC expliclity on the receiver was I able to confidently tell on which NIC the IGMP join will be issued, and on which NIC the program will be listed (via ip maddr) as having joined the MC group; by setting the Sender onto specific NIC's it is readily verified, that a send on enp0s3 will only reach a receiver on enp0s3, and not enp0s8 (similarly, the tcpdump shows the packets as outbound on the chosen interfaces). This is so, of course, without starting to play with MC routing on the OS, which can be made to route the packets as wished for,
You may imagine a setup like yours, where two different NICs will lead to completely separated LAN's, which may further have all/complete elements of MC routing (designated routers, perhaps rendezvous points etc). Thus, selecting the proper NIC for IGMP joins is essential and determines everything; if these are issued to wrong NIC, you may not be able to receive MC traffic; if they are issued to both NICs, you may get more than you want.
I hope this helps (even if the question is 6 years old by now);

IIRC MulticastSocket is for receiving multicasted messages, and you need to configure it with setGroup to listen for multicast messages bound for a specific multicast IP address.
If you want to send a multicast message things are much simpler: you just send your message to that specific multicast IP address and the router/gateway will handle the actual multicasting logic for you. (So you do need to have a router/gateway which supports multicasting properly.)
EDIT: the Java tutorials cover this topic as well: http://docs.oracle.com/javase/tutorial/networking/datagrams/broadcasting.html

The IP address in the setInterface() method is the address of one of your own interfaces. This is used in the case where you have multiple NICs, all connected to different subnets, and you want your multicast join and leave group messages to go out to a subnet that isn't the default route as per the IP routing tables.
In the case you mention there is no need to call setInterface() at all.
If you want a machine to receive messages it does have to be turned on.

Related

Java multicast listening and IGMP

I have an issue that is driving me crazy! Both design-wise and tech-wise.
I have a need to listen to a LOT of multicast addresses. They are divided into 3 groups per item that I am monitoring/collecting. I have gone down the road of having one process spin-up 100 threads. Each thread uses 2 ports, and three addresses/groups. (2 of the groups are on same port) I am using MulticastChannel for each port, and using SELECT to monitor for data. (I have used datagram but found NIO MulticastChannel much better).
Anyway, I am seeing issues where I can subscribe to about a thousand of these threads, and data hums along nicely. Problem is, after a while I will have some of them stop receiving data. I have confirmed with the system (CentOS) that I am still subscribed to these addresses, but data just stops. I have monitors in my threads that monitor data drops and out-of-order via the RTP headers. When I detect that a thread has stopped getting data, I do a DROP/JOIN, and data then resumes.
I am thinking that a router in my path is dropping my subscription.
I am at my wits end writing code to stabilize this process.
Has anyone ever sent IGMP joins out the network to keep the data flowing? Is this possible, or even reasonable.
BTW: The computer is a HP DL380 Gen-9 with a 10G fiber connection to a 6509 switch.
Any pointers on where to look would really help.
Please do not ask for any code examples.
The joinGroup() operation already sends out IGMP requests on the network. It shouldn't be necessary to send them out yourself, and it isn't possible in pure Java anyway.
You could economize on sockets and threads. A socket can join up to about 20 groups on most operating systems, and if you're using NIO and selectors there's no need for more than one thread anyway.
I have used datagram but found NIO MulticastChannel much better).
I don't know what this means. If you're referring to DatagramSocket, you can't use it for receiving multicasts, so the sentence is pointless. If you aren't, the sentence is meaningless.

How to limit the scope of multicast explicitly to 1 hop only?

It's my first question here, so my apologies if I asked wrongly.
In my experiment, multiple android devices are connected using WiFi Direct. To make use of the broadcast nature of wireless tx, all the devices join a single multicast group to exchange their information. My intention is to let the sender send only one copy of its information, while all the 1-hop neighbors receives it.
My trouble is, nodes further away are also receiving it.
Consider the example:
A----B----C
at the same time:
A----D
1) connection is done by wifi direct;
2) they join a single multicast group for message exchange.
What I want: if A sends, B and D can receive, not C; if B sends, A and C can receive, not D. Basically the so-called "1-hop broadcast".
What I get: if A sends, B and D receives, B helps relay it (due to mac layer multicast established by udp multicast I guess?) so C also receives it.
I did some search, multicastSocket has a setTimeToLive() method, with parameters as:
0: not sent on network, only local use;
1: only local network, not going through router;
...
But I somehow need something between 0 and 1, so I can limit the tx to only 1-hop. I couldn't find a solution to this.
You might ask why I need to limit the scope. That's for preventing the flooding, thus reducing network resource consumption.
You might ask why not using unicast to each neighbors. This has a scalability issue in terms of neighbor set cardinality, which should be efficiently solved by multicast/broadcast. Unless wifi direct actually "simulates" multicast/broadcast using unicast at mac layer?
You might also ask why don't I create one distinct multicastSocket for each node to let his neighbors join. I have thought about this, but not sure about the complexity of managing all those sockets.
Sorry for having written so long. I'm looking forward for any suggestion.
EDIT:
--- We tried to setTimeToLive(1), but nodes 2 hops away from a sender can still receive the message.
--- We checked the default TTL and confirmed the default value is already 1.
--- My feeling is that TTL doesn't decrease as it goes from hop to hop, it merely limits the transmission within a "local network" i.e., not going through routers. With wireless nodes connected by WiFi Direct, the network may be treated as a single "local network", hence the relay to all multicast group members.
--- So I doubt if there is any way to explicitly limit the transmission hop counts for a multicastSocket.
--- My two UGLY backup plans are:
1) unicast from a sender to each of its 1-hop neighbors; or
2) each node maintains its own multicastSocket, to let each of its neighbors to join. So nodes 2-hops away will join different multicast groups.
But both solutions will cause the creation and close of lots of sockets, and are subject to the scalability issue (i.e., density).
Can anyone suggest any better solutions to do this? Basically the key target is: implement the 1-hop broadcast functionality for wireless nodes to share local information to its 1-hop neighbors.
Best
Zhang Bo
In C, you have to set the socket option for TTL (Time to Live):
u_char ttl;
setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,sizeof(ttl))
In java you have different options:
MulticastSocket.setTimeToLive: http://docs.oracle.com/javase/7/docs/api/java/net/MulticastSocket.html#setTimeToLive(int)
Other options:
Use StandardSocketOptions class to set socket options: http://docs.oracle.com/javase/7/docs/api/java/net/StandardSocketOptions.html#IP_MULTICAST_TTL
To use StandardSocketOptions you need to work with DatagramChannel:
http://docs.oracle.com/javase/7/docs/api/java/nio/channels/DatagramChannel.html
DatagramChannel channel = DatagramChannel.open();
int ttlValue = 1;
channel.setOption(StandardSocketOptions.IP_MULTICAST_TTL, ttlValue);

Java: How to make a multicast IP InetAddress exclusive?

I'm trying to make a multicast IP exclusive, i.e. it can be "locked" and when it is "locked", no more MulticastSocket can join it.
Is it possible? How do I do it? Here's some code to explain my case:
String multicastIP = "224.0.0.1"; //multicast IP to "lock" later
InetAddress group = InetAddress.getByName(multicastIP); //create group
MulticastSocket multicastSocket = new MulticastSocket(8800); //Create a MulticastSocket using port 8800
multicastSocket.joinGroup(group); //join the group
//This is the part where I want to "lock" the group/IP
Additional information:
I'm developing a network game where the single server to multiple clients broadcasting scheme is done via this method.
There was a time we created two servers (that happen to have the same multicast IP) and incidentally, the clients listen to both servers, receiving messages from both servers.
What we want to happen is to make the clients listen only to their respective servers.
Thanks! :D
Multicast won't do this for you.
You will have to examine each incoming packet when you receive it and match it against the (source address, source port) tuple the client is sending from.
Honestly I don't think there is much advantage to using muticast for this. One approach I have seen is to use multicast for service discovery, and then use unicast for the "real" protocol once you have discovered it.
Edit: For a LAN application, multicast may be acceptable. I would just be careful not to broadcast too much. (multicasts are essentially broadcasts to most switches; they are filtered out by the NIC rather than the network) That is, ideally make sure the server is the one sending the multicast traffic while the clients unicast updates to the server. (if every client multicasts state updates that all other clients can see, what's the purpose of having the server?)

get IP addresses of computer available on a network? -java

I am making a file sharing application which would look for computers which are running the application on the same network. So I would like my application to discover computers and their IP address. Is this task achievable using Java?
thanks
This is one of the basic problems in distributed computing, and there are two approaches that work, to a degree:
Registry Service
Somewhere on the network, you run a Registry Service with a well-known host and port number. This service has to be reachable / addressable from every place you want to run the application.
On startup each instance of the application on the network registers itself with the registry.
When some machine / program needs to locate an instance of the application, it asks the registry.
Problems:
You have to deal with application instances that "go away" without telling the registry.
You have to have a way to restore state if the registry restarts.
The applications have to know the name (or address) and port of the registry instance.
Broadcast / Multicast
Every instance of the application listens on a well-known "broadcast" or "multicast" address / port.
When a program wants to locate instances of the application, it sends a broadcast / multicast request.
Each instance responds to the request giving its details.
The program accumulates the responses to build a list of all "live" instances.
Problems:
This doesn't scale. Each and every request from M programs goes to N machines and generates N responses. As M and N grow, the network traffic grows quadratically.
Broadcast and Multicast are lossy, especially on busy networks.
Broadcast typically doesn't cross network boundaries. Multicast requires special configuration.
Either approach should work on a small network with a limited number of instances.
The simple approach is to identify an existing distributed computing technology that does most of the work for you. For example, RMI and a RMI registry, dynamic DNS, CORBA, JINI.
I found the answer to this question..I looked around and found this code. It is not the best way to do it but it works..
import java.io.IOException;
import java.net.InetAddress;
public class networkPing {
public static void main(String[] args) throws IOException {
InetAddress localhost = InetAddress.getLocalHost();
// this code assumes IPv4 is used
byte[] ip = localhost.getAddress();
for (int i = 1; i <= 254; i++)
{
ip[3] = (byte)i;
InetAddress address = InetAddress.getByAddress(ip);
if (address.isReachable(1000))
{
System.out.println(address + " machine is turned on and can be pinged");
}
else if (!address.getHostAddress().equals(address.getHostName()))
{
System.out.println(address + " machine is known in a DNS lookup");
}
}
}
}
One problem here is that 'the same network' isn't well defined. Do you mean a subnet? All the nodes reachable prior to a router?
If for example you mean 'the LAN', this has no meaning in TCP, but SAMBA might be of help.
Some of that can be addressed by using appropriately scope multicast, if you can get the other nodes to respond. Or if you know the subnet mask you can just do IP address arithmetic. But you need to define your problem more precisely first.
You should take a look at this article on jxta. It's sun's P2P framework for Java and it's used by a ton of popular applications. It might also be good to look at some applications that use jxta, because they may already do something like what you're trying to do.
Either use multicast DNS (I do not know how you can use it on Java/Windows).
Or use IP broadcast (with UDP).
Each computer should send DatagramPacket s to a multicast group. Also receive packets from the group. then use getAddress() to get InetAddress object from packet.
Remember: to receive multicast packets, the system should join the multicast group. But anyone (no need to join) can send packets to a multicast group.
Example is here.
I found this utility class part of Apache commons JCS (a caching library) particularly helpful, just copied it to my project since I didn't want/need to include the whole JCS library and the code is not available elsewhere separately (e.g. in apache commons-net would be nice):
HostNameUtil Javadocs
HostNameUtil.java source

Java: Determine receiving address when receiving with MulticastSocket

I am using MulticastSocket to receive UDP Multicast packets. How can I determine to which address such a packet was sent? With the methods provided, I am only able to determine the sender address.
Of course, I am the one who sets the To-Address when creating the listening socket, but can I really be sure about this? What about broadcast packets? What about packets that somehow end up here?
I really want to distinguish if the packet was REALLY multicast.
Thank you!
Update: Currently it seems like unicast packets just sent to that port also end up in the multicast sockets receive() :( Binding to devices also gives me no better results
I'm a bit fuzzy on the details but a multicast packet will have been sent to the ip/port combo you subscribed to (and this info will be in the packet, somewhere), assuming you managed to have a clear path of intermediary routers that understand multicast. If you want to make sure the multicastsocket is receiving from the right network interface, there's a bunch of functions to bind it to a specific interface.
I don't think you have any way of knowing if the packet was "really" multicast, i.e. someone could always forge one, since there's no real security built in.

Categories