I'm writing a multicast-based messaging program in java. For flow control of the messages, I'd like each member of the group to maintain a list of all of the other members in the group. I could do this by assigning each member a separate ID that gets sent along with the data, but I'd like to differentiate them based on address.
The only problem is, I am running many instances of the program from my local machine, so they all have the same address. Each member of the group runs a listener in a separate thread that listens for messages on a certain port of the specified multicast IP, and each sender sends to that port. Would it be possible to assign a separate port for each sender? Would the receiver be able to listen on all ports?
The receiver binds to a port using:
address = InetAddress.getByName(multicastIP);
socket = new MulticastSocket(this.port);
socket.joinGroup(address);
And messages are sent using:
packet = new DatagramPacket(data, data.length, address, port);
socket.send(packet);
I'd like to differentiate them based on address.
The only problem is, I am running many instances of the program from my local machine, so they all have the same address.
So you can't differentiate them based only on address.
Would it be possible to assign a separate port for each sender?
Yes, if they all use different sockets.
Would the receiver be able to listen on all ports?
The receiver doesn't need to listen on different ports. You only send to one port, you only need to receive on one port.
The problem with this comes if senders are also receivers. If that's the case it won't work: you will have an explosion of ports and you will basically have to multicast to all known ports, which isn't multicasting at all really. In which case you will need to devise a unique client ID, say a UUID.
Related
I want to simulate a network on my computer.
I want to send each packet with a different IP address.
How do I set the IP address on the Socket?
For example, I want to set my IP address is 192.168.1.1 or 192.168.1.1/24.
How do I do?
I only know how to set the port number.
private static DatagramSocket socket;
socket = new DatagramSocket(1024);
Can I use
DatagramSocket(int port, InetAddress laddr)
to initial my socket?
if yes, what should I input in the parameter "laddr"?
Assuming you mean set the source IP address - you can't. A UDP socket is bound to a particular IP interface (or interfaces) on your computer. The IP interface is what 'has' the address. A program using IP sockets only gets to choose which existing interface to use.
Note that even if you could arbitrarily set the source-address field in an outgoing datagram, there would be no simple way to receive any reply - because there's nothing on your computer responding to your chosen address (there is no IP interface at that address).
If you want to simulate having different IP addresses in a program,, you'll need to simulate IP. That would involve using raw sockets, but there does not seem to be a Java implementation for that.
I develop client-server application, working in real-time. Server and clients exchanges by small messages, so I choose UDP for my architecture (as suggested in many articles in network).
It's not a problem for me to use default java's DatagramSocket/DatagramPacket for orginizng all things as I want, but when I read documentation I see the "MulticastSocket" opportunity.
But it is completely unclear for me: How MutlicastSocket at the user side will know where to connect? (public IP/port of the server). Really, as this shown at this official java tutorial.
MulticastSocket creates like:
MulticastSocket socket = new MulticastSocket(4446);
InetAddress group = InetAddress.getByName("203.0.113.0");
socket.joinGroup(group);
and there is NO any specification about public server IP and port.
What is "203.0.113.0"? It is possibles that tones of applications send something to that address in web, isn't it?
When I create client in regular (not Multicast) way I use something like:
DatagramSocket outputClientSocket = new DatagramSocket();
DatagramPacket outputPacket = new DatagramPacket(new byte[512],512,InetAddress.getByName("94.***.89.***"),9898);
...
where "94.???.89.???" is my server's public IP address, and 9898 is port of my server, that listens it. Like that:
DatagramSocket serverInputSocket = new DatagramSocket(9898);
DatagramPacket inputServerPacket = new DatagramPacket(new byte[512],512);
serverInputSocket.recieve(inputServerPacket);
and after recieving something I can establish connection with client, and answer something for him, like that:
DatagramSocket socketForSpecificClient = new DatagramSocket();
InetAddress realClientAddress = inputServerPacket.getAddress();
int realClientPort = inputServerPacket.getPort();
DatagramPacket packetForSpecificClient = new DatagramPacket(new byte[512],512,realClientAddress,realClientPort);
socketForSpecificClient.send(packetForSpecificClient);
This approach works well, even if client has no public IP.
It is absolutely clear way of establishing connection for me, but I can't understand for what purposes MulticastSocket should be used?
Multicast is in IPv4 usually not working across network segments. If your application is supposed to work on the internet (and not e.g. just within an intranet under your control), you can not base your communcation on multicast.
Edit: Here are some further resources on the subject:
Wikipedia on IP multicast:
multicast services are generally not available to the average end-user
Other Stackoverflow question 'UDP Multicast over the internet?':
In general this is not possible since multicast packages aren't routed.
Discussion on hardforum.com 'Does multicast work over the itnernet(sic)?':
ISPs filter mutlicast you can't join a multicast stream over the internet.
These are just a few of the first hits when googling for 'using multicast over the internet'.
The address range 203.0.113.0/24 is reserved for use in 'documentation and example code' so the address in the example, 203.0.113.0, does not point to a real endpoint.
If you need a real, public multicast address and are connected through an ISP with multicast support, you have to obtain one from the IANA registry. You are right that anyone can send (potentially bogus) data to that IP address, but you have exactly the same problem with unicast addresses. If you provide a service on a unicast address, anyone can connect to that address and send data to it.
Quoting the paragraphs from the book Java Network Programming for framing the answer :
How MutlicastSocket at the user side will know where to connect?
(public IP/port of the server)?
What is "203.0.113.0"? It is possibles that tones of applications send
something to that address in web, isn't it?
Firstly, you should generally use IP-Address lying between 225.0.0.0 to 238.255.255.255 for creating a new multicast group.
When a host wants to send data to a multicast group, it puts that data in multicast datagrams, which are nothing more than UDP datagrams addressed to a multicast group. Multicast data is sent via UDP.
A multicast address is the shared address of a group of hosts called a multicast group. IPv4 multicast addresses are IP addresses in the CIDR group 224.0.0.0/4 (i.e., they range from 224.0.0.0 to 239.255.255.255).
A multicast group is a set of Internet hosts that share a multicast address. Any data sent to the multicast address is relayed to all the members of the group. Membership in a multicast group is open; hosts can enter or leave the group at any time. Groups can be either permanent or transient. The IANA is responsible for handing out permanent multicast addresses as needed.
Multicasting sends data from one host to many different hosts, but not to everyone; the data only goes to clients that have expressed an interest by joining a particular multicast group. In a way, this is like a public meeting. People can come and go as they please, leaving when the discussion no longer interests them. Before they arrive and after they have left, they don’t need to process the information at all: it just doesn’t reach them. On the Internet, such “public meetings” are best implemented using a multicast socket that sends a copy of the data to a location (or a group of locations) close to the parties that have declared an interest in the data.
In the best case, the data is duplicated only when it reaches the local network serving the interested clients: the data crosses the Internet only once. More realistically, several identical copies of the data traverse the Internet; but, by carefully choosing the points at which the streams are duplicated, the load on the network is minimized. The good
news is that programmers and network administrators aren’t responsible for choosing the points where the data is duplicated or even for sending multiple copies; the Internet’s routers handle all that.
To receive data that is being multicast from a remote site, first create a MulticastSocket with the MulticastSocket() constructor. As with other kinds of sockets, you need to know the port to listen on. This code fragment opens a MulticastSocket that listens on port 2300:
MulticastSocket ms = new MulticastSocket(2300);
Next, join a multicast group using the MulticastSocket ’s joinGroup() method:
InetAddress group = InetAddress.getByName("225.2.2.2");
ms.joinGroup(group);
This signals the routers in the path between you and the server to start sending data your way and tells the local host that it should pass you IP packets addressed to the multicast group.
Once you’ve joined the multicast group, you receive UDP data just as you would with a DatagramSocket .
It is possibles that tones of applications send something to that
address in web, isn't it?
One would face the same problem even in case of unicast communication if the address is known on which the service is provided.
Is there a way to send a UDP packet inside a LAN so that every machine receives it? (Of course no guarantees because its UDP).
Like, sending a request "Hello, anybody out there?" and then listening for a response?
I got no problem with sending and receiving, just want to know if there's a way other than trying out every IP address possible...
Edit: This is what I use at the moment:
...
multicastSocket = new MulticastSocket();
multicastSocket.setBroadcast(true);
broadcastGroup = InetAddress.getByName("255.255.255.255");
// multicastSocket.joinGroup(broadcastGroup);
...
The last line of code is commented out because it throws an exception. Now I've read that sending a packet to 255.255.255.255 is "deprecated since years" and most likely won't work on many LANs. Also, I'm not sure if I even need a MulticastSocket for this or if a normal DatagramSocket would work as well. But anyway, what would be the preferred way to send a UDP broadcast nowadays?
Well, I found it out by myself:
Just open a MulticastSocket and use joinGroup on any IP between 224.0.0.0 and 239.255.255.255. Of course everything related to that multicast group needs to receive on the same multicast IP.
I did it for sending AND receiving, however, I think you only need it when receiving messages. When you want to broadcast a packet to everybody in the IP group, just send it to the IP you selected.
You should also do setBroadcast(true); to allow broadcasting for certain (?) systems.
Technically speaking you actually need to broadcast the message. Basically you need MulticastSocket, this kind of socket is used on the client-side to listen for packets that the server broadcasts to multiple clients.
Here is the java tutorial to help you achieve that:
http://docs.oracle.com/javase/tutorial/networking/datagrams/broadcasting.html
I want to know that how can we know the IP address of client on server side in socket (java). Suppose there is a server "S" and 2 clients "A" and "B". Client A send me(server) some info, and Client B send me(server) some other info. I have to store that info coming from A and B in database in different tables. How can I Differentiate between client A and B request.?
Each socket has a getInetAddress() method which returns the IP address of the client connected to it.
The other answer has addressed your core question. I just want to add that there are some circumstances where the IP address you get back does not uniquely identify the true endpoint; i.e. the user's PC.
If two users are using the same system to connect; i.e. it is a multi-user system.
If the user's PC is behind a NAT gateway (because it has a private / site-local IP address), then the IP address you will get will be for the gateway.
It is also for the address to have been spoofed or hijacked in some way ...
There is nothing you can do to detect either of these situations from the server side. You just need to be aware of them, and not rely on the (supposed) client IP address as being definitive.
So ...
How can I Differentiate between client A and B request?
In any of the above circumstances, you cannot distinguish A and B by IP address alone. If you look at the connections to A and B while both connections are alive, they will have different remote port numbers. But those port numbers only last for the duration of the connection. However, next time A or B connects, A could be using the remote port that B was using, or vice versa.
I'm writing a UDP server, which is a first for me; I've only done a bit of TCP communications. And I'm having trouble figuring out exactly how to distinguish which user is which, since UDP deals only with packets rather than connections and I therefore cannot tell exactly who I'm communicating with.
Here is pseudocode of my current server loop:
DatagramPacket p;
socket.receive(p); // now p contains the user's IP and port, and the data
int key = getKey(p);
if(key == 0) { // connection request
key = makeKey(p);
clients.add(key, p.ip);
send(p.ip, p.port, key); // give the user his key
} else { // user has a key
// verify key belongs to that IP address
// lookup the user's session data based on the key
// react to the packet in the context of the session
}
When designing this, I kept in mind these points:
Multiple users may exist on the same IP address, due to the presence of routers, therefore users must have a separate identification key.
Packets can be spoofed, so the key should be checked against its original IP address and ignored if a different IP tries to use the key.
The outbound port on the client side might change among packets.
Is that third assumption correct, or can I simply assume that one user = one IP+port combination? Is this commonly done, or should I continue to create a special key like I am currently doing?
I'm not completely clear on how TCP negotiates a connection so if you think I should model it off of TCP then please link me to a good tutorial or something on TCP's SYN/SYNACK/ACK mess.
Also note, I do have a provision to resend a key, if an IP sends a 0 and that IP already has a pending key; I omitted it to keep the snippet simple. I understand that UDP is not guaranteed to arrive, and I plan to add reliability to the main packet handling code later as well.
UDP packet headers have a source port, which is generally used as the reply port. If not used, it should be zero, and then it is up to the higher level protocol to figure out how to coordinate request-response activity with multiple clients.
* The outbound port on the client side might change among packets.
Is that third assumption correct
Not if the client keeps using the same outbound socket. Sending the first datagram will cause a local bind, so the socket will be on a fixed local port from then on.
Your questions are just the tip of the iceburg WRT laundry list of issues you need to be aware of when using UDP. You should expect NAT routers to fail to provide any meaningful forwarding of a UDP protocol you design. TCP works because the routers understand the TCP state machine and store connection state of each session so they know how to forward it. They will have no idea how your custom UDP protocol works. NAT devices include specific protocol handlers for well known UDP applications.
If a sender is bound to a source port and or interface the senders source ports remain constant until unbound.
With UDP you can bind both peers to a known source port for (dst) incoming and or (src) outgoing messages. For client/server applications you typically want the client to bind to a dynamic source port so that multiple clients can co-exist on a single client system. The server can then respond to the client using the dynamic source port provided via the src port from request used as destination port in the response. Using a known port for peers allows you to configure UDP forwarding in NAT devices.
ex client/server with server on known port 3000
client binds to a random port (1234) but knows server is listening on port 3000.
client (src 1234) -> server (dst 3000)
server (dst 1234) -> client (src 3000)
...
If a computer has multiple interfaces you should expect to either need to explicitly bind a listener or sender to a specific IP address or be able to handle requests and responses from a peer being sent and recieved from a random IP based on the whims of the computers routing table. If you choose to bind requests to a specific interface then you need to be cognizant of the routing table if messages from a multi-homed system need to transit a different local interface for delivery. For example if you bind a UDP socket to 127.0.0.1 you obviously can't use it to send to any Internet routable IP Addresss.
In terms of protocol design its common to frame a session id and sequence fields in the UDP payload so that peers can keep track of sessions and individual exchanges.
There are a whole host of fragmentation, NAT coexistance, security and congestion issues you need to be aware of to successfully design a robust UDP protocol. I advise against it unless absolutely necessary.