5
votes

I am currently exploring UDP packet transmission in Java to create a multiplayer game on Android. I succeeded at exchanging packets within my Nexus 4 by using the usual "127.0.0.1" and I also succeeded at exchanging packets between my PC server and my Android client in my local network. But since I will want my game to be playable on the Internet, I want my Android client to be able to exchange packets with my PC server when they aren't on the same local network. This is where I am struggling.

My setup : A PC server connected with my home Internet connection and a Nexus 4 connected with a 3G network.

First, my PC server starts listening on the port 10000 and my Android client opens a socket to receive server's packets on port 10001. Then, the Android client sends a packet to the PC server to its current public address "173.246.12.125" on port 10000. The PC server receives the packet and sends a response to the sender on port 10001. But the Android client never receives the response.

Here is my PC server code :

public class UDPServer {
    private final static int SERVER_PORT = 10000;
    private final static int CLIENT_PORT = 10001;

    public static void main(String[] args) {
        InetAddress clientAddr = null;
        DatagramSocket socket = null;
        try {
            //Initializing the UDP server
            System.out.println(String.format("Connecting on %s...", SERVER_PORT));
            socket = new DatagramSocket(SERVER_PORT);
            System.out.println("Connected.");
            System.out.println("====================");
        } catch (UnknownHostException e1) {
            e1.printStackTrace();
        } catch (SocketException e) {
            e.printStackTrace();
        }

        while(true){
            try {
                //Listening
                byte[] buf = new byte[1024];
                DatagramPacket packet = new DatagramPacket(buf, buf.length);
                System.out.println("Listening...");
                socket.receive(packet);

                //Getting client address from the packet we received
                clientAddr = packet.getAddress();
                System.out.println("Received: '" + new String(packet.getData()).trim() + "' from "+clientAddr.toString());

                //Sending response
                byte[] message = ("Hello Android").getBytes();
                DatagramPacket response = new DatagramPacket(message, message.length, clientAddr, CLIENT_PORT);
                DatagramSocket clientSocket = new DatagramSocket();
                System.out.println("Sending: '" + new String(message) + "'");
                clientSocket.send(response);
                System.out.println("Response sent.");
                System.out.println("--------------------");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

And here are my Android client classes :

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        new Thread(new Receiver()).start();
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(new Client()).start();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

}

public class Receiver implements Runnable {
    private final static int LISTENING_PORT = 10001;

    @Override
    public void run() {
        try {
            //Opening listening socket
            Log.d("UDP Receiver", "Opening listening socket on port "+LISTENING_PORT+"...");
            DatagramSocket socket = new DatagramSocket(LISTENING_PORT);
            socket.setBroadcast(true);
            socket.setReuseAddress(true);

            while(true){
                //Listening on socket
                Log.d("UDP Receiver", "Listening...");
                byte[] buf = new byte[1024];
                DatagramPacket packet = new DatagramPacket(buf, buf.length);
                socket.receive(packet);
                Log.d("UDP", "Received: '" + new String(packet.getData()).trim() + "'");
            }
        } catch (Exception e) {
            Log.e("UDP", "Receiver error", e);
        }
    }
}

public class Client implements Runnable {
    private final static String SERVER_ADDRESS = "173.246.12.125";//public ip of my server
    private final static int SERVER_PORT = 10000;

    @Override
    public void run() {
        try {
            //Preparing the socket
            InetAddress serverAddr = InetAddress.getByName(SERVER_ADDRESS);
            DatagramSocket socket = new DatagramSocket();

            //Preparing the packet
            byte[] buf = ("Hello computer").getBytes();
            DatagramPacket packet = new DatagramPacket(buf, buf.length, serverAddr, SERVER_PORT);

            //Sending the packet
            Log.d("UDP", String.format("Sending: '%s' to %s:%s", new String(buf), SERVER_ADDRESS, SERVER_PORT));
            socket.send(packet);
            Log.d("UDP", "Packet sent.");
        } catch (Exception e) {
            Log.e("UDP", "Client error", e);
        }
    }
}

The server's console is showing the IP of the client :

Connecting on 192.168.1.126:10000...
Connected.
====================
Listening...
Received: 'Hello computer' from /204.48.72.68
Sending: 'Hello Android'
Response sent.
--------------------
Listening...

The packet seems to come from the address 204.48.72.68, but if I go on whatismyip.com on my Android, it shows me 96.22.246.97... I don't know where 204.48.72.68 is coming from...

I am not sure if the problem is that my listening socket on my Android client is not good or if the PC server does not send the response to the correct address. Could someone points me what am I doing wrong?

Thank you

2
you might be having trouble with the lifecycle developer.android.com/reference/android/app/…Ray Tayek
If I understand what you are telling me, even if my receiver is run in a new thread and the app is sending it's message at the creation of the activity, Android might kill my receiver's process within the ms following the creation of the activity?Raphael Royer-Rivard
i am not an expert, but something like that may be happening. maybe some printouts or debugging would prove useful.Ray Tayek
I can confirm that it is not the problem, I just set a timeout of 3000ms to my listening socket and after 3 seconds it pops a timeout exception, so the thread is still alive. The problem is elsewhere.Raphael Royer-Rivard

2 Answers

2
votes

I came across a similar issue, but I was using TCP Sockets instead of UDP. My intense was sending files directly to a mobile. In LAN this worked pretty much. It appears, that's not possible to send data to listening sockets, when your phone is connected to internet using the mobile connection. I've read on some pages (sry dont have any links anymore), that incoming connections on a mobile phone is blocked by the telecommunications provider. My workaround was to create outgoing connections to the server and use the bidirectional possiblities of tcp sockets. Maybe you can use your "working" datagram socket, to exchange data with your mobile. Here is an example, which i had found: http://itucet.blogspot.de/2011/03/java-bidirectional-data-transfer-using.html

1
votes

Same code working well for me, Have an issue when tried with emulator but its works fine if you use any android mobile .

The reason for the issue is android emulator and your computer are not in same subnet .