Here's the problem, it's very simple (to understand..):
I have 2 computers at home, they both have the same public IP address (e.g. 1.2.3.4).
I have 1 computer at a coffee place (different network) so it has a different public IP address.
I want to send a message (e.g. "hi") from the computer at the coffee place to ONE of computers I have at home.
I'm using Java, think of the following very simple program for the sender (I took off exception handling for simplicity):
In main I do:
sendPacket("hi");
and I have
void sendPacket(String message){
DatagramSocket myServerSocket = new DatagramSocket(9000); // server socket
byte[] sendData = new byte[message.length()]; // build msg
sendData = message.getBytes();
InetSocketAddress destSocketAddr = new InetSocketAddress("1.2.3.4", 9000); // destination socket addr
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, destSocketAddr); // make packet
myServerSocket.send(sendPacket); // send packet
}
If I have my listener (receiver) running on both computers at home (both with the same public IP address 1.2.3.4) how can I specify which one I intend to send this message to?
If both of your home computers have the same public IP address, that means those computers are using NAT or Network Address Translation (strictly speaking, it's Port Address Translation or NAT Overload, but commonly referred to as just NAT).
What this means is that in order to initiate a connection from the outside to any of your machines inside NAT, a Port Forwarding must be set in your router (typically your modem), so that you map a specific port of your public home IP address to a specific private IP address inside your home.
Let's say you have computers A and B in your home like this:
Router / Modem
192.168.0.1
||
++=========++========++
|| ||
Computer A Computer B
192.168.0.2 192.168.0.3
Now, let's assume you need Computer A listening on TCP port 9000
(ports can mainly be TCP or UDP), you could forward public port 9000
directly to Computer A's 9000
port:
Forward TCP/UDP on public port 9000 to private port 9000 on 192.168.0.2
To send a message to computer A, just send it to 1.2.3.4:9000
. But what if the other PC only listens on port 9000
too? You cannot also assign public port 9000
because it is taken by Computer A. You could do this:
Forward TCP/UDP on public port 9001 to private port 9000 on 192.168.0.3
This way, computer B still receives messages on port 9000
, but they would need to be sent across the Internet to 1.2.3.4:9001
. Your router's NAT automatically translates the port as the data packets enter (and leave!) your home network.
In the end, the sender would need to adjust the destination port in order to 'talk' to different machines behind NAT.
Hope this makes sense.
Typically, these NAT firewalls will port-forward traffic back to the originating computer for you.
So, if you had one machine sending traffic to your coffeeshop machine on port 5000
and the other one sending traffic to the coffeeshop machine on port 5001
, the router would keep track of which port is intended for which client. Thus, when you send packets back from port 5000
it'll go to the first machine, and when you send packets back from port 5001
, it'll go to the second machine.
The unfortunate part is that your machine at the coffeeshop is probably also behind a NAT firewall, and your home machines may not be able to directly address it, either.
If you can host a server on a good network, then both peers can contact the server, and relay all traffic through it. That's not a bad option but it does not scale well. (For three machines, it's no big deal. For three million machines, it matters a lot.)
You can investigate other options to try to traverse the NAT firewall such as UPnP, but those mechanisms usually require some way for clients to negotiate sessions before they'll work.