Allahjane
Allahjane

Reputation: 1978

Android can send udp but not receive

I've written a basic udp client server where one android sends message to the server and server relays it to the rest of the clients.

The issue is, the incoming udp messages get to the server and server relays them back but they never reach the rest of the devices.

Whats really amazing is that if I use the server as echo server (i.e relaying only to sender) then everything works. All client and server sockets use same port 2706

Server code

while (true) {
    DatagramPacket packetToReceive = new DatagramPacket(new byte[2048], 2048);
    try {
        listenerSocket.receive(packetToReceive);
        InetAddress senderAddress = packetToReceive.getAddress();
        relayedBytes += packetToReceive.getLength();

        if (!connectedClients.contains(senderAddress)) {
            connectedClients.add(senderAddress);
        }

        for (InetAddress addr : connectedClients) {
            // commenting this line will make it an echo server
            if (!addr.equals(senderAddress))
            {
                //The following actually prints the ips of the android
                //devices so it knows where to send

                System.out.println(senderAddress.getHostAddress().toString() +
                    " to " + addr.getHostAddress().toString());
                byte[] data = packetToReceive.getData();
                packetToReceive.setData(data, 0, packetToReceive.getLength());
                packetToReceive.setAddress(addr);
                listenerSocket.send(packetToReceive);
            }
        }
    } catch (IOException) {
        e.printStackTrace();
    }
}

android sender logic:

mainSocket=new DatagramSocket(homePort);

//targetAddressString is the public IP of server
target = InetAddress.getByName(targetAddressString);
while (true) {
    byte[] data = getdata();
    if (data == null)
        continue;
    DatagramPacket packet = new DatagramPacket(data, data.length, target, targetPort);

    mainSocket.send(packet);
}

meanwhile on other thread the reciever just waits with the same udp socket:

while (true) {
    Log.d("Player", "Waiting for data");
    DatagramPacket packet = new DatagramPacket(new byte[2048], 2048);
    try {
        mainSocket.receive(packet);
        Log.d("Player", "packet received");
        //do something with the packet
    } catch (IOException e) {
        e.printStackTrace();
    }
}

It never moves further than waiting for data since it'll block until it receives a packet

Moreover I can also see it in the wifi and Mobile data icons that no data is ever received but data sending is always on and is seen received on the server

**EDIT:- Echo server **

while (true) {
    DatagramPacket receivedPacket = new DatagramPacket(new byte[2048], 2048);
    try {
        listenerSocket.receive(receivedPacket);
        InetAddress senderAddress = receivedPacket.getAddress();
        if (!connectedClients.contains(senderAddress)) {
            connectedClients.add(senderAddress);
        }

        for (InetAddress addr : connectedClients) {
            byte[] data = receivedPacket.getData();
            DatagramPacket sendPacket= new DatagramPacket(data,  0, receivedPacket.getLength(), addr, receivedPacket.getPort());
            listenerSocket.send(sendPacket);
        }
    } catch (IOException e) {
        // ...
    }
}

Basically it should relay the message to every single client who've ever sent any data but somehow it only sends its to its original sender the rest of clients miss it. the code is trolling with me

Upvotes: 1

Views: 3550

Answers (2)

selbie
selbie

Reputation: 104524

This is the NAT traversal problem as you have figured out.

Here's a few hints:

  1. The server can be hardcoded to listen on port 2706. But it shouldn't make any assumptions about what source port of received packets are. From your code, it doesn't look like you ever attempt to call setPort. So even if the NAT wasn't mapping your port number differently, I'm not sure how your original code was even getting the any destination port set. But I think you figured this out based on your own answer and your updated code.

  2. Don't hardcode a client port on the client's socket. Choose port "0" (or don't set one) on your socket to let the OS choose the first available port for you. If you have multiple clients behind the same NAT, this behavior will allow for quicker client restarts, multiple devices behind the same NAT, and other nice things.

Upvotes: 3

Allahjane
Allahjane

Reputation: 1978

Holly Molly! I finally figured it out , it was my own fault I wasn't considering my cellphone provider's Nat and was assuming 2706 port in public IP as well.

Turns out actually I was under my cellphone network's NAT and my port 2706 was converted to some hideous port number by the time it reached the server. So I had to consider the port no of the actual packet received rather than the one set on the phone.

In a nutshell it was like this

cellphone (port 2706)-> NAT (port 40234) -> Server (port 40234)

and so I was actually trying to send back data to 2706 instead of 40234 -_-'

Once I start to send back the packets at 40234 (or whatever came with the packet) instead of 2706 , it gracefully followed the path back to my android cellphone and everything was fine.

Upvotes: 2

Related Questions