Akke
Akke

Reputation: 33

Simple Java UDP server/client-program works on local machine but not over either LAN (different machines) or internet

Probably the final update I think I've found the problem. I'm behind a CGNAT ("thanks" to my internet provider) which means that I share a public ip-address with other random strangers, which in turn means that port-forwarding on my router will do nothing since my router is effectively using a private ip-address.


Yet another update: I'm making progress, but still haven't come all the way. The program I'm trying to get to communicate is a game written in Java, so I'm creating an exe-file from a runnable-jar (exported via Eclipse) and then wrapping that to create an exe-file using Launch4j.

I noticed through wireshark that the client program when run as an exe-file on the laptop did not send any udp-packets (it only sent them when receiving packets as a server in response, never by itself when trying to join as a client). After exhausting every other option I just tried to create another exe-file using the most up to date code, and that resolved this particular problem (as to why I have no idea, I didn't touch the network code, I wish I knew what I actually did to get it working, but alas...).

Now the situation is the following. Packets ARE being sent, this is verified on every computer I've tried it on, my own or at my friends computer. The program now can communicate both-ways when on the same network. The program can NOT communicate over the internet, no packets reach the destination. I've tried this both locally with two machines on the same network (but trying to connect to the public ip instead of the local ip) and with my friends computer (that is in another network in another city) as client (he verified through wireshark that packets are being sent with the correct target ip and the correct target port).

So packets are being sent, but no packets are arriving, even with all firewalls turned off (windows and router) and the relevant ports forwarded. Anyone have any ideas about what might be the problem? Can you do some sort of traceroute but with udp-packets to see where they are being dropped/blocked?


Update to problem: I can connect to my laptop (acting as host) from my main computer (acting as client) using the local network address of the laptop (with port forwarding enabled). I can NOT connect the other way around, i.e with the main computer acting as host and laptop acting as client. I still can not connect either way if I use the public ip-address, and I still require help. Maybe this is a piece of the puzzle for somebody?

stationary computer (client, win 8.1) --> local network --> laptop (server, win10) == works!

laptop (client, win10) --> local network --> stationary computer (server, win 8.1) == does not work

All other combinations with external computers, public ip-addresses etc == does not work


I have a program where the user can enter the servers ip-address and port-number and then (in theory) establish a peer2peer connection and send/receive udp datagrams. I will first outline the problem, then what I've tried, and finally the relevant code.

Problem:

I can connect and send udp datagram packets between the server and client if I start two instances of the program on the same computer (one server, one client), using the local network ip-address as the server address (if I use the external internet address this does not work).

I can not receive any udp packets on either the server or the client when I try to run the client on one machine and the server on another, both machines in the same network. Neither public nor local network address works, nothing gets through to the server.

The same problem exists if I try to set up a host/client on my own machine and an external machine (e.g a friends computer outside my network).

The program is set up so that the client will send data to the server, and if any data gets through, the server will respond. Using wireshark I can see that no udp packets are reaching the server from the client.

What I've tried:

I've tried to open up my port (port forwarding) on my router, but this had no effect. I've checked so that the firewall isn't blocking the port, but allowing the chosen port in the firewall (both in/out) had no effect. I've searched for information but I have not found anything else to help me. I have also verified through Wireshark that udp datagrams are actually sent regularly by the client to the ip-address/port combination that was specified (i.e, the client is actually sending packets but they aren't arriving).

The relevant code:

First a brief explanation regarding the program logic. The server first chooses a port number then waits for incoming data. The client chooses a server ip and a server port, then tries to send udp datagram packets to the server. The server reacts to the first udp-packet that arrives on the port the server is listening to, and sends data back to the ip-address and port that it can get from the received udp datagram.

Server code

public class UdpServer {

    private int clientPortNumber = 0; 
    private InetAddress clientAddress = null; 
    
    private DatagramSocket socket = null; 
    
    public ConcurrentLinkedQueue<byte[]> receiveBuffer_threadSafe = new ConcurrentLinkedQueue<byte[]>(); // thread safe
    public ConcurrentLinkedQueue<byte[]> sendBuffer_threadSafe = new ConcurrentLinkedQueue<byte[]>(); // thread safe
    
    private volatile boolean runDataReceptionThread = true; 
    public Thread dataReceptionThread;
    private volatile boolean runDataSendingThread = true;
    public Thread dataSendingThread;
    
    public UdpServer(int serverPortNumber) // chosen by server before class is instantiated
    {
        try 
        {
          socket = new DatagramSocket(serverPortNumber); // server will listen on this port
        } 
        catch (SocketException e) 
        {
            e.printStackTrace();
        }
    }
    
    private void setClientPortNumber(int clientPortNumber)
    {
        this.clientPortNumber = clientPortNumber; 
    }
    
    public void startReceivingThread()
    {
        dataReceptionThread = new Thread()
        {
          public void run()
          {
            while (runDataReceptionThread)
            {
                DatagramPacket receivedDatagram = new DatagramPacket(receiveBuffer, receiveBuffer.length);
                
              try 
              {
                socket.receive(receivedDatagram);
                    
                if (clientAddress == null)
                {
                    clientAddress = receivedDatagram.getAddress();
                    setClientPortNumber(receivedDatagram.getPort()); 
                }

                receiveBuffer_threadSafe.add(receiveBuffer.clone());
                  
              } 
              catch (Exception e) 
              {
                e.printStackTrace();
              }
            }
          }
        };

        dataReceptionThread.start();
    }
    
    public void startSendingThread()
    {
        dataSendingThread = new Thread()
        {
          public void run()
          {
            while (runDataSendingThread)
            {
              if (clientAddress != null)
              {
                if (!sendBuffer_threadSafe.isEmpty())
                {
                  byte[] dataToSend = sendBuffer_threadSafe.poll();
                    
                  DatagramPacket datagramToSend = new DatagramPacket(dataToSend, dataToSend.length, clientAddress, clientPortNumber);
                      
                  try 
                  {
                    socket.send(datagramToSend);
                  } 
                  catch (Exception e) 
                  {
                    e.printStackTrace();
                  }
                }
              }
            }
          }
        };

        dataSendingThread.start();
    }
    
    public void killServer()
    {
        runDataReceptionThread = false; 
        runDataSendingThread = false; 
        
        try 
        {
          socket.close();
        } 
        catch (Exception e) 
        {
          e.printStackTrace();
        }
    }

Instantiating a server

    public void createNewUdpServer(int serverPortNumber)
    {
        udpServer = new UdpServer(serverPortNumber); 
        
        udpServer.startReceivingThread();
        udpServer.startSendingThread();
    }

Client code

public class UdpClient {

    private InetAddress serverAddress = null; 
    private int serverPortNumber = 0; 
    
    private DatagramSocket socket = null; 

    public ConcurrentLinkedQueue<byte[]> receiveBuffer_threadSafe = new ConcurrentLinkedQueue<byte[]>(); // thread safe
    public ConcurrentLinkedQueue<byte[]> sendBuffer_threadSafe = new ConcurrentLinkedQueue<byte[]>(); // thread safe
    
    private volatile boolean runDataReceptionThread = true; 
    public Thread dataReceptionThread;
    private volatile boolean runDataSendingThread = true;
    public Thread dataSendingThread;
    
    public UdpClient (String ipString, int serverPort) // input by user prior to instantiation
    {
        try 
        {
          serverAddress = InetAddress.getByName(ipString);
        } 
        catch (UnknownHostException e) 
        {
          e.printStackTrace();
        }
        
        try 
        {
            serverPortNumber = serverPort;
            
            socket = new DatagramSocket(); // no port specified for client
        } 
        catch (SocketException e) 
        {
            e.printStackTrace();
        }
    }
    
    public void startReceivingThread()
    {
        dataReceptionThread = new Thread()
        {
          public void run()
          {
            while (runDataReceptionThread)
            {
              DatagramPacket receivedDatagram = new DatagramPacket(receiveBuffer, receiveBuffer.length);
              try 
              {
                socket.receive(receivedDatagram);
                receiveBuffer_threadSafe.add(receiveBuffer.clone());
              } 
              catch (IOException e) 
              {
                e.printStackTrace();
              }
            }
          }
        };

        dataReceptionThread.start();
    }
    
    public void startSendingThread()
    {
        dataSendingThread = new Thread()
        {
          public void run()
          {
            while (runDataSendingThread)
            {
              if (!sendBuffer_threadSafe.isEmpty())
              {
                byte[] dataToSend = sendBuffer_threadSafe.poll();
                  
                DatagramPacket datagramToSend = new DatagramPacket(dataToSend, dataToSend.length, serverAddress, serverPortNumber);
                      
                try 
                {
                    socket.send(datagramToSend);
                } 
                catch (IOException e) 
                {
                  e.printStackTrace();
                }
              }
            }
          }
        };

        dataSendingThread.start();
    }
    
  public void killClient()
  {
    runDataReceptionThread = false; 
    runDataSendingThread = false; 
        
    try 
    {
      socket.close();
    } 
    catch (Exception e) 
    {
      e.printStackTrace();
    }
  }
}

Instantiating a client

    public void createNewUdpClient(String serverIpAddress, int serverPortNumber)
    {
        udpClient = new UdpClient(serverIpAddress, serverPortNumber); 
        
        udpClient.startReceivingThread();
        udpClient.startSendingThread();
    }

Making the server/client send data (example shows only the server, but they use the same logic, just switch the name from udpServer to udpClient), data added to the sendbuffer of the server or client will be send as soon as the thread notices that the sendbuffer isn't empty

byte[] dataToSend = new byte[1];

dataToSend[0] = 1; 
                    
udpServer.sendBuffer_threadSafe.add(dataToSend);

Please help me, I'm fumbling in the dark at the moment.

Upvotes: 1

Views: 518

Answers (1)

Akke
Akke

Reputation: 33

I'm answering my own question just to conclude it. Turns out I was put behind a CGNAT (Carrier-Grade NAT). This basically means that I shared my public external-facing IP with other customers of my ISP. This seems to be some sort of middle-step solution to the current shortage of ipv4-addresses, before the majority has switched over to ipv6. The way it seems to be set up is that I have a public ip that's shared with other people, then my router gets a private ip that's in a certain ip-range, and then I in turn of course have private ip:s for my home computers. Since tcp/udp-packets expect to arrive at the router and then be forwarded to the correct pc in the network immediately, this extra step jumbles things up enough so that port forwarding on your own router will not work (you'd have to do port forwarding on whatever router/switch/whatever that's connected to your public ip, and that's not possible of course since it's shared with other people, you don't have a personal "owned" public ip that points to your specific home network).

Anyway, a quick call to my ISP-provider fixed the issue at no extra cost.

Upvotes: 1

Related Questions