Search code examples
javaandroidudpdatagram

Java UDP socket echoing bytes


I'm writing an android source(but just java) to communicate with some embedded device which acts as a server.

I am sure that my UDP datagrams are arriving to the device since I can observe the device state changing.

But the problem is that I am failing to get response from the server. Not receiving nothing, but I just get an echo of what I sent. My source is as below.

 public void sendSnapShot(View view) {
 //send a udp datagram to the server.
    new AsyncTask<Void, Void, Void>() {
        @Override
        protected Void doInBackground(Void... voids) {

            try {
                Log.e("Test", "send sendSnapShot onLine");

                DatagramSocket clientSocket = new DatagramSocket();

                byte[] sendData = new byte[1024];

                String sentence = "$SNAPSHOT";

                sendData = sentence.getBytes();


                DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getByName("192.168.5.255"), 9999);
                clientSocket.send(sendPacket);

                Log.e("Test", "Sent sendSnapShot REQUEST");

            } catch (Exception e) {
                Log.e("Test", "e", e);
            }

            return null;
        }
    }.execute();
}

The above code is about transfering datagram to the server. On the start of the application, the below thread will be started to listen for any datagram sent by the server.

 private class ListenerThread implements Runnable {
    //listen for incoming datagrams.
       @Override
       public void run() {
           DatagramSocket serverSocket = null;
           try {
            InetAddress serverAddr = InetAddress.getByName("192.168.5.255");
            serverSocket = new DatagramSocket(9999, serverAddr);

            while (true) {
                try {

                    byte[] receiveData = new byte[1024];

                    DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
                    serverSocket.receive(receivePacket);
                    receivePacket.getLength();
                    String receivedData = new String(receivePacket.getData(), 0, receivePacket.getLength());
                    if (!receivedData.startsWith("!HEARTBEAT")) {
                        Log.e("Test", "Received : " + receivedData);
                    } else {
                        Log.e("Test", "Received : HEARTBEAT");
                    }
                } catch (Exception e) {
                    Log.e("Test", "FROM SERVER ", e);

                }
            }
 } catch (Exception e) {
            Log.e("Test", "Exception", e);
            }
        }
    }

The guy who wrote the server code(probably written in c++) says that he is getting response in his test case, so what may I be missing? Is there a possiblity that the above code will ignore any datagram from the server and echo bytes sent from my code?

=============================================================================

I've changed my code according to the answer. I no longer use the listening thread anymore. Here's my code.

public void sendBattery(View view) {
        new AsyncTask<Void, Void, Void>() {
        @Override
        protected Void doInBackground(Void... voids) {

            try {
                Log.e("Test", "send Battery onLine");

                DatagramSocket clientSocket = new DatagramSocket(9999, InetAddress.getByName("0.0.0.0"));

                byte[] sendData = new byte[1024];
                byte[] receivedata = new byte[1024];

                String sentence = "$S0B255";
                DatagramPacket receivePacket = new DatagramPacket(receivedata, receivedata.length);

                sendData = sentence.getBytes();
                String receivedData = " ";
                DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getByName("192.168.5.1"), 9999);
                clientSocket.send(sendPacket);
                do{
                    clientSocket.receive(receivePacket);
                    receivedData = new String(receivePacket.getData(), 0, receivePacket.getLength());
                    Log.e("Test", receivedData +  ", IP CHECK Sender:  : " + receivePacket.getAddress().toString() + ", port : "+ receivePacket.getPort());
                }while(true);
               // Log.e("Test", "Sent BATTERY REQUEST COMPL");
            } catch (Exception e) {
                Log.e("Test", "e", e);
            }

            return null;
        }
    }.execute();
}

According to the heartbeat byte(making it to a string will make it "!HEARTBEAT") i'm receiving, the sender is 192.168.5.1. But still, I only get heartbeat bytes only. What shall I be missing?


Solution

    • You are receiving your own datagrams, because you are broadcasting (to 192.168.5.255). You should use the device's actual IP address.
    • You should not create a new datagram socket per send. (You are never closing that socket, so you are also leaking sockets.)
    • You should send the datagrams from the same socket you are receiving on. The device will (should) reply to the IP:port the request came from, and at present that's different every time, and you're losing the sending socket that's bound to that port, and the sending IP:port isn't the IP:port you're listening on, so you don't hear it.
    • You should not bind your listening socket to a specific IP address, and certainly not to a broadcast address. I'm surprised it works.