Android UDP packet loss : why? - java

I'm writing an android app which consist of udp communication with some linux machine(a very low spec machine with camera).
The machine consists of an rtsp server, and a udp server which responds to certain keywords and responses via udp packet.
The hardware developer says that there was nothing wrong when he tested it with his laptop, but losses are accurring in my android device.
Below is my source.
It will send a single command, and the device will send back two packets with length of 10 for each.
Can someone inspect if there are any faults that may cause loss in this source?
private DatagramSocket clientSocket;
public void stopUdpSocket(){
try {
if (clientSocket != null) {
clientSocket.close();
}
}catch (Exception e){
Log.e("test", "error", e);
}
}
public void sendUdp(final Context context, final String command, final Handler handler) {
new AsyncTask<Void, Void, List<String>>() {
#Override
protected List<String> doInBackground(Void... voids) {
Log.e("Test", "send $SNAPSHOT onLine");
try {
clientSocket = new DatagramSocket(9999, InetAddress.getByName("0.0.0.0"));
byte[] sendData = new byte[1024];
byte[] receivedata = new byte[1024];
String sentence = command;
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);
List<String> temp = new ArrayList<>();
List<String> result = new ArrayList<>();
int timeoutCounter = 0;
do {
if (timeoutCounter == 4) {
try {
Log.e("Test", "UDP TIMEOUT");
clientSocket.close();
} catch (Exception e) {
Log.e("test", "Execption", e);
}
return null;
}
clientSocket.receive(receivePacket);
receivedData = new String(receivePacket.getData(), 0, receivePacket.getLength());
Log.e("Test", receivedData + ", IP CHECK Sender: : " + receivePacket.getAddress().toString() + ", port : " + receivePacket.getPort());
if (!receivedData.equals("!HEARTBEAT")) {
Log.e("Test", "ADD : " + receivedData);
temp.add(receivedData);
timeoutCounter = 0;
}
if (temp.size() == 2) {
break;
}
receivePacket = new DatagramPacket(receivedata, receivedata.length);
timeoutCounter++;
} while (true);
clientSocket.close();
Log.e("Test", "End of UDP TASK - client socket closed");
for (String s : temp) {
result.add(s.substring(2, s.length() - 1));
}
return result;
} catch (Exception e) {
Log.e("Test", "e", e);
}finally {
stopUdpSocket();
}
return null;
}//end of doInBackground
}.execute();
}//end of sendUdp

UDP is a Connection Less Protocol which doesn't guarantee Data Delivery at the Communication Layer. You need to implement a Protocol in your Application Layer to guarantee Data Delivery. SEND XXX, ACK XXX. If you don't receive an ACK you must resend the Data.
Or simply you use TCP which Connection Oriented and Guarantees Delivery.

Related

Receive message from multicast socket on another host (from aws server instance)

I want to send/receive messages by the multicast socket.
This is my code
'''
public class MulticastSender {
public static final String GROUP_ADDRESS = "230.0.0.1";
public static final int PORT = 7766;
public static void main(String[] args) throws InterruptedException {
DatagramSocket socket = null;
try {
// Get the address that we are going to connect to.
InetAddress address = InetAddress.getByName(GROUP_ADDRESS);
System.out.println("GROUP_ADDRESS: " + address);
// Create a new Multicast socket
socket = new DatagramSocket();
DatagramPacket outPacket = null;
long counter = 0;
while (true) {
String msg = "Sent message No. " + counter;
counter++;
outPacket = new DatagramPacket(msg.getBytes(), msg.getBytes().length, address, PORT);
socket.send(outPacket);
System.out.println("Server sent packet with msg: " + msg);
Thread.sleep(1000); // Sleep 1 second before sending the next message
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (socket != null) {
socket.close();
}
}
}
'''
'''
public class MulticastReceiver {
public static final byte[] BUFFER = new byte[4096];
public static void main(String[] args) {
MulticastSocket socket = null;
DatagramPacket inPacket = null;
try {
// Get the address that we are going to connect to.
SocketAddress address = new InetSocketAddress(MulticastSender.GROUP_ADDRESS, MulticastSender.PORT);
// Create a new Multicast socket
socket = new MulticastSocket(address);
socket.joinGroup(address, NetworkInterface.getByName("eth0"));
while (true) {
// Receive the information and print it.
inPacket = new DatagramPacket(BUFFER, BUFFER.length);
socket.receive(inPacket);
// System.out.println(socket.getInterface());
String msg = new String(BUFFER, 0, inPacket.getLength());
System.out.println("From " + inPacket.getAddress() + " Msg : " + msg);
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
'''
It is working on my local host. however, I want to send messages from my AWS server instance (with public ipv4) and receive them in the local client. How to do it?
if yes, please give me an example!
Tks all

How to run 2 main methods in parallel threads?

I have two following classes (including only main methods for simplicity)
public class UDPServer {
public static void main(String[] args) throws IOException {
int serverPort = 9876;
DatagramSocket socket = new DatagramSocket(serverPort);
byte[] buffer = new byte[1024];
boolean isConnected = true;
while (isConnected) {
try {
DatagramPacket request = new DatagramPacket(buffer, buffer.length);
socket.receive(request);
DatagramPacket reply = new DatagramPacket(
request.getData(),
request.getLength(),
request.getAddress(),
request.getPort()
);
socket.send(reply);
} catch (IOException ex) {
isConnected = false;
Logger.getLogger(UDPServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
public class UDPClient {
public static void main(String[] args) {
String pathToQuery = getUserInput();
List<Packet> queried = UDPServer.getQueriedServerDataTypes(pathToQuery);
try {
if (args.length < 1) {
System.out.println("Usage: UDPCLient <msg> <server host name>");
System.exit(-1);
}
// Create a new datagram socket
DatagramSocket socket = new DatagramSocket();
// Preferred IPv4 address (cmd: ipconfig/all)
InetAddress host = InetAddress.getByName(args[0]);
int serverPort = 9876;
for (int i = 0; i < queried.size(); i++) {
Packet dataType = queried.get(i);
String requestFile = "data_type_request_v" + (i + 1) + ".txt";
UDPServer.saveToFile(
dataType,
"Server request.",
requestFile
);
// Serialize Packet object to an array of bytes
byte[] data = Tools.serialize(dataType);
System.out.println("Sent: " + Arrays.toString(data));
// Request datagram packet will store data query for the server
DatagramPacket request = new DatagramPacket(
Objects.requireNonNull(data),
data.length,
host,
serverPort
);
// Send serialized datagram packet to the server
socket.send(request);
// The reply datagram packet will store data returned by the server
DatagramPacket reply = new DatagramPacket(data, data.length);
System.out.println("Reply: " + Arrays.toString(reply.getData()));
// Acquire data returned by the server
socket.receive(reply);
// Store deserialized data in null Packet object.
Packet read = (Packet) Tools.deserialize(data);
System.out.println("Reading deserialized data...\n" + read.toString());
String responseFile = "data_type_response_v" + (i + 1) + ".txt";
UDPServer.saveToFile(
read,
"Server response.",
responseFile
);
boolean isResponseEqualRequest = UDPServer.isResponseEqualRequest(
requestFile,
responseFile
);
if (isResponseEqualRequest) {
System.out.println("Communication successful. Server response corresponds to the request.");
} else {
System.out.println("Communication unsuccessful. Server response does not correspond to the request.");
}
}
// Close the datagram socket
socket.close();
} catch (IOException | ClassNotFoundException ex) {
Logger.getLogger(UDPClient.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
In order for the UDPClient to work properly, UDPServer has to be running in the background. I want to run the UDPServer.main() in parallel thread and as soon as UDPClient.main() finishes, the thread should terminate as well.
How do I do that?

How do i receive data

My listener ->
public void startListening(){
String[] details = session.split(":");
SessionUser user = new SessionUser();
System.out.println("Waiting for another user..");
listening = new Thread("listen thread"){
public void run() {
while(true) {
while (user.users < 2) {
try {
Socket socket1 = socket.accept();
System.out.println(socket1.getInetAddress().toString() + " has joined...");
user.users++;
socket1.close();
} catch (Exception e) {
System.out.println("Ran into a error!");
}
}
}
}
};
listening.start();
}
My sender ->
public void join(InetAddress address, int port){
byte[] data = new byte[1024];
DatagramPacket packet = new DatagramPacket(data, data.length, address, port);
try {
DatagramSocket socket = new DatagramSocket();
System.out.println("Attempting to join session <" + address.toString() + ":" + port + ">!");
socket.send(packet);
System.out.println("Joining......");
}catch (Exception e){
System.out.println("Unable to connect, this may be a server error, or you've entered incorrect details!");
}
}
So i just want to send packets to the hosts server upon connecting, however, when i run this i am not seeing any sort of output, here is a picture that will probably explain it better then i can -> click me
Change your server to receive the packets as well
DatagramSocket serverSocket = new DatagramSocket(port);
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
serverSocket.receive(packet); // This will block until a packet is received
System.out.println("Received: " + new String(packet.getData()));
Try testing with your client
public void join(InetAddress address, int port){
byte[] data = "Hello".getBytes();
DatagramPacket packet = new DatagramPacket(data, data.length, address, port);
try {
DatagramSocket socket = new DatagramSocket();
System.out.println("Attempting to join session <" + address.toString() + ":" + port + ">!");
socket.send(packet);
System.out.println("Joining......");
}catch (Exception e){
System.out.println("Unable to connect, this may be a server error, or you've entered incorrect details!");
}
}
If you need to maintain a connection, it's better to use TCP with Sockets.
In your receiver, you're reading from a TCP socket, whereas your sender is sending an UDP packet. This cannot work.

MulticastSocket doesn't open port

I'm trying to create a simple multicast communication between my PC (Ubuntu, client) and my phone (Android, server).
Unicast/TCP connections work without any problem, the defined port (37659) opens both on PC and phone. When trying to use a MulticastSocket, no ports get opened. nmap tells me the specified port (36963) is a TCP port and that it is closed. (While the receive-method is being executed).
Am I doing something wrong? Or is the firewall blocking the multicast sockets? (I've tried about 20 different ports and none worked..., currently using port 36963)
EDIT: Also with the firewall completely down, nmap tells me the port is closed...
The server's code (phone):
private void multicastLoop() {
String res = Build.FINGERPRINT + "\n";
final InetAddress group;
final MulticastSocket socket;
final DatagramPacket response;
try {
group = InetAddress.getByName("224.0.0.115");
socket = new MulticastSocket(mport);
socket.setLoopbackMode(true);
socket.setSoTimeout(10000);
socket.joinGroup(group);
response = new DatagramPacket(res.getBytes(), res.length(), group, mport);
} catch (IOException e) {
e.printStackTrace();
return;
}
Thread t = new Thread(new Runnable() {
#Override
public void run() {
while(isRunning) {
try {
byte[] data = new byte[1024];
DatagramPacket dm = new DatagramPacket(data, data.length);
socket.receive(dm);
Log.d("udp", "received");
if (Arrays.equals(dm.getData(), "someone there".getBytes())) {
socket.send(response);
}
} catch (SocketTimeoutException e) {
continue;
} catch (IOException e) {
e.printStackTrace();
}
}
try {
socket.leaveGroup(group);
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
t.start();
}
The client's code (computer):
public String[] findServers() {
String hello = "someone there";
try {
InetAddress group = InetAddress.getByName(mhost);
MulticastSocket socket = new MulticastSocket(mport);
socket.setLoopbackMode(true);
socket.setSoTimeout(60000);
socket.joinGroup(group);
DatagramPacket p = new DatagramPacket(hello.getBytes(), hello.length(), group, mport);
byte[] buffer = new byte[1024];
socket.send(p);
DatagramPacket r = new DatagramPacket(buffer, buffer.length);
socket.receive(r);
socket.leaveGroup(group);
socket.close();
String srinfo = "";
byte[] data = r.getData();
for (byte b: data)
srinfo += (char) b;
System.out.println("Server found at " + r.getAddress().getHostName() + ": " + srinfo);
} catch (SocketTimeoutException e) {
return new String[] {"timeout"};
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
Make sure mhost is set to "224.0.0.115" not some machine name.
Make sure multicast is enabled on your router.
If the host is multi-homed, you need to join the multicast group via all local interfaces, not just the default one, which is what you're doing at present.
You could send the response back to the source address it came from, which is in the received datagram packet. That would also mean that the client doesn't need a MulticastSocket, only a DatagramSocket.

same server listening on different sockets

I have a UDP multicast server listening on 2 sockets on 2 different ports. I achieved listening on these 2 sockets from clients. But i want to identify on which socket a client is sending a packet. Since my problem is that ; on the server if I listen on socket(9999) and if the client is sending on socket(8888) then at the server side I want it to identify the incoming packet is from which port.
public class MulticastReceiver
{
public static void main(String[] args)
{
MulticastSocket socket = null;
DatagramPacket packet = null;
MulticastSocket soc = null;
byte[] inBuf = null;
try
{
socket = new MulticastSocket(8888);
soc = new MulticastSocket(9999);
InetAddress address = InetAddress.getByName("224.2.2.3");
socket.joinGroup(address);
soc.joinGroup(address);
System.out.println("224.2.2.3 ready to receive packets");
while(true)
{
inBuf=new byte[256];
packet = new DatagramPacket(inBuf,inBuf.length);
System.out.println("port is: "+ packet.getAddress() + packet.getPort());
if(packet.getPort() == 9999)
{
soc.receive(packet);
//System.out.println("Data at 224.2.2.3:: " + new String(packet.getData()));
}
else
socket.receive(packet);
System.out.println("Data at 224.2.2.3:: " + new String(packet.getData()));
}
}
catch(Exception e)
{
}
}
}
public class MulticastSender {
public static void main(String[] args) {
DatagramSocket socket = null;
DatagramPacket outPacket = null;
byte[] outBuf;
final int PORT = 8888;
try {
socket = new DatagramSocket();
long counter = 0;
String msg;
msg = "This is multicast! ";
outBuf = msg.getBytes();
//Send to multicast IP address and port
InetAddress address = InetAddress.getByName("224.2.2.3");
outPacket = new DatagramPacket(outBuf, outBuf.length, address, PORT);
socket.send(outPacket);
System.out.println("Server sends : " + msg);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
} catch (IOException ioe) {
System.out.println(ioe);
}
}
}
public class AnotherSender {
public static void main(String[] args) {
DatagramSocket socket = null;
DatagramPacket outPacket = null;
byte[] outBuf;
final int PORT = 9999;
try {
socket = new DatagramSocket();
long counter = 0;
String msg;
msg = "This is another multicast! " + counter;
counter++;
outBuf = msg.getBytes();
//Send to multicast IP address and port
InetAddress address = InetAddress.getByName("224.2.2.3");
outPacket = new DatagramPacket(outBuf, outBuf.length, address, PORT);
socket.send(outPacket);
System.out.println("Server sends : " + msg);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
} catch (IOException ioe) {
System.out.println(ioe);
}
}
}
Your code doesn't make sense. The packet won't have a port number at all until you put one into it or receive() does, and at best this will just read alternately between the two sockets, blocking each time, possibly forever, receiving from one socket, and thus starving the other one.
You need a receiving thread for each non-blocking socket.

Categories

Resources