Java UDP - Client doesn't receive DatagramPacket without forwarding ports

Hello there!
I am making a 2D game engine in pure Java in which includes a built-in network/multiplayer feature. The network feature is self-hosted by a player, where other players/clients can connect to the host. The network feature is UDP based because of the importance of net speed. Another note is that i don’t want any external libraries involved in this. I want to do it purely with what the standard Java library has to offer.

I don’t want the clients/end-users having to manually forward any ports in order to make this work. The host should only need to do that at most.

Things are working out perfectly when testing locally between two running applications on the same computers. But the issue begins when trying it out with other people from around the world.

This is a rundown of how things are going down when trying it out:

[quote]> HOST opens a DatagramSocket on port 1234, waiting for CLIENT to send a message (this is used to accept clients and create “Connections” with new threads for each client)

CLIENT opens a DatagramSocket on port X (automatically assigned to a free one)
CLIENT creates two threads using the same DatagramSocket. One for listening and one for sending
CLIENT sends a message to HOST
HOST receives message (where it also gets the IP/port of CLIENT)
HOST creates two threads using the same DatagramSocket. One for listening and one for sending ()
HOST sends message to CLIENT

CLIENT never receives message
[/quote]
I have confirmed that the IP/port for sending/receiving between the client and host are correct. There is no one sending a message to the wrong IP/port.

I can send as many messages i like without any change. The host has port forwarded port 1234 for incoming packets. The client hasn’t port forwarded anything in the example up above.

Just to make sure this one time i asked one of the clients/testers to forward a port, which made it work just fine. So the issue is definitely related to the ports.

I tried doing TCP instead of UDP, using Socket instead of DatagramSocket which made it work just fine as long as the host had the port forwarded to begin with. The only backside was that it became practically unplayable due to slow network speed, so i am desperately looking for a solution to this UDP issue.

I also tried to use both TCP and UDP, using the same TCP Socket port for the UDP DatagramSocket port. Where i first established a connection using a TCP Socket just to later create a UDP DatagramSocket for sending/receiving on the same port. This did not work either.

Connection class (inside Network.java):

class Connection
{
  String NAME;
  InetAddress IP;
  int PORT;    
  DatagramSocket DSOCKET;
  boolean ENABLED = true;

  public Connection(InetAddress ip, int port,String name)
  {
    IP = ip;
    PORT = port;
    NAME = name;
    try
    {
      DSOCKET = new DatagramSocket();
      receive();
      send();
    }catch(Exception e){}
  }
  public void send()
  {
    Thread sendthread = new Thread()
    {
      public void run()
      {
        try
        {
          byte[] sendData;
          while(ENABLED)
          {
              try
              {
                  String message = "Hello there!";
                  sendData = new byte[message.getBytes().length];
                  sendData = message.getBytes();
                  DatagramPacket sendPacket = new DatagramPacket(sendData,sendData.length,IP,PORT);
                  DSOCKET.send(sendPacket);
              }catch(Exception e){System.out.println("NetSendError: " + e);}
          }
          DSOCKET.close();
        }catch(Exception e){}
      }  
    };
    sendthread.start();
  }
  public void receive()
  {
    Thread thread = new Thread()
    {
      public void run()
      {
        byte[] receiveData;
        try
        {
          DSOCKET.setSoTimeout(1000);
          while(ENABLED)
          {
            receiveData = new byte[4096];
            DatagramPacket receivePacket = new DatagramPacket(receiveData,receiveData.length);
            DSOCKET.receive(receivePacket);
            String message = new String(receivePacket.getData());
            System.out.println("CLIENT received message: " + message);
          }
        }catch(Exception e){}
      }
    };
    thread.start();
  }
}

Network.java:

import java.util.Vector;
import java.net.*;

public class Network
{
  boolean HOSTING = false;
  public static Vector<Connection> CONNECTIONS = new Vector<Connection>();
  
  public static void main(String[] args)
  {
    starthost();
    try
    {
      InetAddress ip = InetAddress.getByName("193.150.248.134");
      connect(ip,1234);
    }catch(Exception e){}
  }

  //called by host when starting a hosted session
  public static void starthost()
  {
    boolean HOSTING = true;
    Thread thread = new Thread()
    {
      public void run()
      {
        try
        {
          DatagramSocket socket = new DatagramSocket(1234);
          byte[] receiveData;
          try
          {
            while(HOSTING)
            {
              try
              {
                receiveData = new byte[4096];
                DatagramPacket receivePacket = new DatagramPacket(receiveData,receiveData.length);
                socket.receive(receivePacket);
                int ii = CONNECTIONS.size();
                boolean exists = false;
                for(int i=0;i<ii;i++)
                {
                  if(CONNECTIONS.get(i).IP.equals(receivePacket.getAddress()))
                  {
                    exists = true;
                    break;
                  }
                }
                if(!exists)
                {
                  //if this is the first time the client sends, create a connection for sending
                  CONNECTIONS.add(new Connection(receivePacket.getAddress(),1234,"HOST"));
                }
                else
                {
                  //if the client exists in the CONNECTION list, print out the received message
                  String message = new String(receivePacket.getData());
                  System.out.println("HOST received message: " + message);
                }
              }catch(Exception e){System.out.println("NetStartHostError: " + e);}
            }
            socket.close();
          }catch(Exception ee){}
        }catch(Exception e){}
      }
    };
    thread.start();
  }

  //called by clients when connecting to host
  public static void connect(InetAddress ip,int port)
  {
    CONNECTIONS.add(new Connection(ip,port,"CLIENT"));
  }
}

With all of this, my following questions are:

[quote]- Am i doing something wrong in the code up above?

  • Is there a way of working around this? (without any external libraries)
  • Should i be using the same DatagramSocket for sending and receiving? Does it make a difference?
  • Is there just no way around this? Does every client needs to port forward manually? If there isn’t, is there a “pure-java” way of port forwarding by code?
  • Why does it work with TCP and not UDP under the same circumstances (host has forwarded ports, client hasn’t)
  • When a client sends a DatagramPacket from a port, shouldn’t it be able to receive packets from the same port?
    [/quote]
    I’m kinda considering giving up on the whole UDP thing and going TCP-only since that actually works. Maybe there’s some methods of speeding it up significantly?
    After more than a week of searching and testing i’m finally creating a thread here. I’d really appreciate some help if there is any available.

Best regards!