So I'm making a simple multiplayer online applet game, and I was testing it using multicast UDP sockets instead of the typical client-server connection. This is not meant to be efficient or safe for that matter, just an experiment. Only problem is, when I try to have other people join the game from their house, it won't connect them to me, but when I use two separate computers, one that's wired in and one that's on the wifi, it works seemlessly. They can join their own game and connect to their own network, but not other peoples. Am I missing something big here? I'll post the relevant code.
InetAddress group;
DatagramPacket packet;
DatagramPacket messagePacket;
MulticastSocket socket;
socket = new MulticastSocket(4446); //random port
group = InetAddress.getByName("228.5.6.7"); //multicast address
socket.joinGroup(group);
//typical code for sending a packet
packet = new DatagramPacket(messageBuf, messageBuf.length, group, 4446);
Any ideas? I'm rather new to networking but find it a fun challenge and would like to continue learning more about it..if you have any other tips on top of helping me to solve this problem it would be appreciated.
You probably figured this out by now, but yes there is a huge problem you are missing. It will always work if you are local because your router doesn't mind distributing packets behind the private LAN. Anything outside the network will not want to work because the client will try to send a packet to the server, but the server is behind a NAT(Network address translation) and since the router didn't see the server send out a packet first, the router will just discard the client's packet and never connect. However if the server sends out a udp packet to try to connect, the router likes to switch ports so you don't know which port the packet will come out of. That's what packet forwarding is for on the router. So when the client sends a packet, it goes to a different port than expected and the router still discards it. There are solutions such as "hole punching". The easiest solution tho is to have a dedicated server outside of any NAT to handle the requests.
Related
I've spent some time learning about UDP connections, particularly with Multicast Sockets in Java.
I was able to make a simple Multicast Socket "group chat" on my local network, but I've since been trying to expand this to work beyond my local network.
In attempts to achieve this, I port-forwarded a Class D IP address on my router in order to allow other people to access my Multicast group from outside my network.
However, when trying to connect to my "group chat" via my public IP and specified port (during the port-forwarding), I would receive the following error message...
Exception in thread "main" java.net.SocketException: Not a multicast address
at java.net.MulticastSocket.joinGroup(MulticastSocket.java:310)
...
This error makes some sense, given that my public IP isn't a class D address. But since I port-forwarded a multicast address to the specified port on my router, shouldn't this problem not occur?
Here's the relevant part of my code...
InetAddress group = InetAddress.getByName("192.___.___.___"); // my public IP
MulticastSocket socket = new MulticastSocket(1234); // the port-forwarded port
socket.joinGroup(group);
Where had I gone wrong here, and how could I get to fixing this issue?
A multicast address is between 224.0.0.0 - 239.255.255.255 with different sub-ranges within for different scenarios. More here: https://en.wikipedia.org/wiki/Multicast_address
So by attempting to join a group at 192.x.y.z, that's an invalid multicast address. That's why you get the exception thrown.
I could be mistaken, I doubt most consumer/home NAT, much less ISPs support multicast traffic. (Begs the questions - whatever happened to the MBONE - I thought that would have taken off and been the solution for everything.)
It sounds like what you need is a proxy program that intercepts multicast traffic and tunnels it to a proxy on a different network running the same code. The proxy in turn, takes the tunnelled packet and redirects back to a multicast\broadcast group.
You might have better luck with broadcast sockets instead of multicast.
I'm new to Java socket programming and I'm currently developing a small peer to peer UDP chatting room application which allow multiple clients to chat with each other.
My question is how do I make a client discover all other connected clients once he hit the connect button providing only one of the connected clients ip and port? The program only runs on local network.
You can use a unique feature of UDP which is broadcasting
On IPv4 (which you are probably using) the address for broadcasting is 255.255.255.255. Any datagram sent to that address will be sent to all UDP clients on the network for that port.
What you can do for your chat application is to have each client send a packet to the UDP broadcast identifying itself, such as maybe the nickname of the user. All the other clients will see that packet, and you will be able to parse the packet and display a list of all the chat clients on the network.
Here is an example of sending a Datagram to broadcast:
DatagramSocket s = new DatagramSocket();
s.setBroadcast(true);
DatagramPacket dp = new DatagramPacket("insert data here".getBytes(), "insert data here".length(), new InetSocketAddress("255.255.255.255", 5000));
s.send(dp);
Another client can receive it like this:
DatagramSocket s = new DatagramSocket();
s.setBroadcast(true);
DatagramPacket dp = new DatagramPacket(new byte[1024], 1024);
s.receive(dp);
The received DatagramPacket will contain the IP and port of the client who had broadcasted it.
One simple possibility would be that every client stores the other peers it knows of and passes the list to any new clients connecting.
Don't forget of authenticating your peers. You can try to use the OpenSSL (very easy) to generate some certificates and use it in association to ssl.
Edit: a bot told me to be more specific so here it is:
Local Networks (LANs) are not always safe, so, to be sure, I would recommend you use OpenSSL to generate certificates for authentication and private keys for encryption, in this way, you can communicate safely.
Python ssl module is a good example.
Backstory:
I have a wireless device which creates it's own SSID, assigns itself an IP address using auto-ip, and begins broadcasting discovery information to 255.255.255.255. (unfortunately, it does not easily support multicast)
What I'm trying to do:
I need to be able to receive the discovery information, then send configuration information to the device. The problem is, with auto-ip, the "IP negotiation" process can take minutes on Windows, etc (during which time I can see the broadcasts and can even send broadcast information back to the device).
So I enumerate all connected network interfaces (can't directly tell which will be used to talk to the device), create a DatagramSocket for each of their addresses, then start listening. If I receive the discovery information via a particular socket, I know I can use that same socket to send data back to the device. This works on Windows.
The problem:
On Linux and OSX, the following code does not receive broadcast packets:
byte[] addr = {(byte)169, (byte)254, (byte)6, (byte)215};
DatagramSocket foo = new DatagramSocket(new InetSocketAddress(InetAddress.getByAddress(addr), PORT_NUM));
while (true)
{
byte[] buf = new byte[256];
DatagramPacket pct = new DatagramPacket(buf, buf.length);
foo.receive(pct);
System.out.println( IoBuffer.wrap(buf).getHexDump() );
}
In order to receive broadcast packets (on Linux/OSX), I need to create my DatagramSocket using:
DatagramSocket foo = new DatagramSocket(PORT_NUM);
However, when I then use this socket to send data back to the device, the packet is routed by the OS (I'm assuming) and since the interface of interest may be in the middle of auto-ip negotiation, fails.
Thoughts on the following?
How to get the "working" Windows behavior to happen on Linux/OSX
A better way to handle this process
Thanks in advance!
I do not think this is the problem with the code. Have you checked if OSX/Linux has correctly allowed those address / port number through their firewalls? I had this simple problem too in the past =P..
FYI, there is a nice technology called Zero-configuration which was built to solve this problem. It is very easy to learn so I recommend you to having a look at that as well.
Good luck.
This question seems like something very obvious to ask, and yet I spent more than an hour trying to find an answer.
First I host and wait for someone to connect. Then, from another instance of the application, I try to connect with a socket - for the constructor, I use InetAddress, port. The port is always right, and everything works if I use "localhost" for the address. However, if I type my IP (the one I got from Googling "what is my ip"), I get an IOException. I even sent the application to someone else, gave him my IP, and it didn't work.
The aim of the application is to connect two computers. It's in Java. Here is the relevant code.
Server:
ServerSocket serverSocket = new ServerSocket(port);
Socket clientSocket = serverSocket.accept();
Client:
InetAddress a = InetAddress.getByName(ip);
Socket s = new Socket(a, port);
I don't get past that. Obviously, the values of int port and String ip are taken from text fields.
Edit: the purpose of my application is to connect two non-local computers.
As mentionned by Greg Hewgill, if you are behind a NAT Device (Router, etc...) you will have to do some Port Forwarding.
Basically, your public IP Address that you get from using "What is my IP" from google is your public IP Address, but since you are using a router with multiple computers connected to it, there is a protocol that maps multiple computers to a single public address called NAT.
What you'll need to do is tell your router to forward the incoming packets on a certain port to a certain computer.
The way to do this is highlighted in this article http://www.wikihow.com/Port-Forward
Here's what I'm trying to do- A server sends out "Alive message to all the PCs on the network and the PCs which are up and running, respond to the call by sending their IP.
I'm looking at a lightweight piece of coding as this will form a small bit of my application.
I've looked at Jini and other services but find that I may not need even half of their features(except for the network discovery)
Is it ok if I:
1. Use a for loop where a server opens a socket, checks(using a for loop) if all the IPs x.x.x.x are reachable by sending an "Alive" message.
2. On receiving the "alive" message at the client at the specific socket, the client replies with its IP.
Is this method OK? Do you think I could do it in a better way?
Thanks!
I had a similar problem a long time ago and I resolved it as follows:
The server broadcasts a UDP packet on the network to 255.255.255.255
All reachable clients will respond with a UDP packet that include their IP and any other information you wish to send.
The packet I personally used looks like
public class UDPDiscoveryPacket{
public final long sendingTime;
public final String clientIP;
public UDPDiscoveryPacket(long sendingTime, String clientIP){
this.sendingTime = sendingTime;
this.clientIP = clientIP;
}
}