I want to implement service discovery by using the network's broadcast address. I am sniffing packets with WireShark to confirm that my UDP packets are not being sent. The network code is not being run on the UI thread. The DatagramSocket.send call returns with no exception thrown, but nothing is seen by other programs including WireShark. I have verified that the address returned by getWifiBroadcastAddress actually is the broadcast address of my network.
I have verified that the network supports broadcast by writing a C# program, run on another machine, and WireShark is detecting broadcast packets from this program.
Here is my Android Java code:
try {
DatagramSocket socket = new DatagramSocket(Protocol.INQUIRY_PORT);
socket.setBroadcast(true);
InetAddress broadcastAddr = getWifiBroadcastAddress();
byte[] data = new byte[10];
for(int i = 0; i < data.length; i++) {
data[i] = (byte) i;
}
DatagramPacket packet = new DatagramPacket(data, data.length,
broadcastAddr, Protocol.INQUIRY_PORT);
while(true) {
// Loops indefinitely, no errors/exceptions
socket.send(packet);
try {
Thread.sleep(5000);
} catch(InterruptedException ie) {
break;
}
}
} catch(IOException ioe) {
// Not logged
Log.d("Broadcast", "Error sending inquiry.");
}
The getWifiBroadcastAddress() method is as seen here: https://lab.dyne.org/AndroidUDPBroadcast
Does anyone know why this would fail silently? Like I said my C# program running on another box is working just fine, doing the same thing, sending the same data every 5s, and WireShark sees those packets, but nothing from the Android phone.
The following works for me, where I can broadcast a particular string value to a specified port (in your case Protocol.INQUIRY_PORT) on the other end(s), and all of the devices on the local subnet that are monitoring UDP on that port can recognize that string value, and accordingly can respond. I am broadcasting from the main thread, but listening for responses in an async task.
public void sendBroadcast(String messageStr) {
// Hack Prevent crash (sending should be done using an async task)
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
byte[] sendData = messageStr.getBytes();
try {
sendSocket = new DatagramSocket(null);
sendSocket.setReuseAddress(true);
//sendSocket.bind(new InetSocketAddress(Protocol.INQUIRY_PORT));
sendSocket.setBroadcast(true);
//Broadcast to all IP addresses on subnet
try {
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getByName("255.255.255.255"), Protocol.INQUIRY_PORT);
sendSocket.send(sendPacket);
System.out.println(getClass().getName() + ">>> Request packet sent to: 255.255.255.255 (DEFAULT)");
} catch (Exception e) {
}
} catch (IOException e) {
Log.e(TAG, "IOException: " + e.getMessage());
}
}
Following is the corresponding UDP response listener code inside an async task class:
protected String doInBackground(String... params) {
serverIP = "";
try {
//Keep a socket open to listen to all the UDP trafic that is destined for this port
InetAddress myHostAddr = InetAddress.getByName("0.0.0.0");
rcvSocket = new DatagramSocket(null);
rcvSocket.setReuseAddress(true);
rcvSocket.bind(new InetSocketAddress("0.0.0.0",Protocol.INQUIRY_PORT));
rcvSocket.setBroadcast(true);
while (true) {
Log.i("VIS","Ready to receive broadcast packets!");
//Receive a packet
byte[] recvBuf = new byte[15000];
DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length);
rcvSocket.receive(packet);
//Packet received
serverIP = packet.getAddress().getHostAddress();
Log.i("VIS", "Packet received from: " + serverIP);
String data = new String(packet.getData()).trim();
Log.i("VIS", "Packet received; data: " + data);
if (!data.equals("") && !data.equals(myInquiryString)) {
//break while loop and return IP address of server
break;
}
}
} catch (IOException ex) {
Log.i("VIS", "ServerDiscovery" + ex.getMessage());
}
return serverIP;
}
Related
I'm going to set a simple socket connection between two android devices using internet.
There are two devices and two android app's , one of them is client app and another is server app.
When the apps run on a device it's all OK, but when the apps run on two devices the client application doesn't connect to server application.
Client app:
btnSend.setOnClickListener(view -> {
String msg = etMessage.getText().toString();
AsyncTask.execute(() -> {
try {
DatagramSocket socket = new DatagramSocket();
InetAddress ip = InetAddress.getByName("100.66.20.245");
int port = 1020;
DatagramPacket packet = new DatagramPacket(
msg.getBytes(), msg.length(), ip, port
);
socket.send(packet);
runOnUiThread(() -> {
Toast.makeText(this, "Message sent", Toast.LENGTH_SHORT).show();
});
} catch (Exception e) {
Log.w(TAG, e.toString());
}
});
});
Server app:
Runnable runnable = () -> {
try {
int port = 1020;
DatagramSocket socket = new DatagramSocket(port);
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer,1024);
runOnUiThread(() -> {
Toast.makeText(this,"Waiting for client",Toast.LENGTH_SHORT).show();
});
socket.receive(packet);
String msg = new String(packet.getData(),0,packet.getLength());
runOnUiThread(() -> {
Toast.makeText(this, "Client msg : " + msg, Toast.LENGTH_SHORT).show();
});
} catch (Exception e) {
Log.w(TAG, e.toString());
}
};
new Thread(runnable).start();
Are both devices connected to a network? And is the IP address of client application equal to the IP address of the server?
The best solution was the port forwarding with a router.
When you are using a router you can set an ip address to forwarding ports to that ip address.
However if you have a better solution, please post a comment :)
Good day,
I am making an Android app which sends UDP packets to Ruby server, which then forwards them to all subscribed android clients, including the original sender.
My server receives the packets, but is not able to send them or connect via UDP socket.
Server code snippet (Ruby, on Fedora 22):
SERVER_SEND_PORT = 4000
ANDROID_PORT = 7500
# Send socket
s_socket = UDPSocket.new
s_socket.setsockopt(Socket::SOL_SOCKET,Socket::SO_BROADCAST, 1)
s_socket.bind(SERVER_IP, SERVER_SEND_PORT)
# Receive socket
r_socket = UDPSocket.new
r_socket.setsockopt(Socket::SOL_SOCKET,Socket::SO_BROADCAST, 1)
r_socket.bind(SERVER_IP, RECEIVE_PORT)
$clientIPs = []
$clientPorts = []
def broadcast(data)
$clientIPs.each_with_index do |ip, index|
puts "trying to send #{data}"
s_socket.connect(ip, ANDROID_PORT) # does not pass this step
puts "connected"
s_socket.send(data, 0)
#s_socket.send(data, 0, ip, ANDROID_PORT)
puts "sent: " + data;
end
end
while true
data, client = r_socket.recvfrom(256)
puts "received: " + data
Thread.new(client) do |clientAddr|
if !$clientIPs.include? clientAddr[3]
$clientIPs << clientAddr[3]
$clientPorts << clientAddr[1]
end
broadcast(data)
end
end
Client code snippet:
private static final int LISTENING_PORT = 7500;
public void onStart() {
/* Unrelated code + Sending socket */
// Receiving Thread
new Thread(){
public void run() {
// Create receiving socket at a given port
try {
rSocket = new DatagramSocket(LISTENING_PORT);
rSocket.setBroadcast(true);
} catch (SocketException e) {
e.printStackTrace();
}
Log.d("Trace", "Created receiving socket");
while (true) {
if (rSocket != null) {
// Receive data
byte[] buf = new byte[256];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
try {
rSocket.receive(packet);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Got the packet!");
}
}
}
}.start();
}
netstat -u does not show any UDP connections in the server.
I have the following code to receive UDP packets:
public class AsyncReceiveUdp2 extends AsyncTask<String, Void, Boolean> {
#Override
protected Boolean doInBackground(String... f_url) {
int udp=111;
byte[] packet = new byte[2000];
DatagramPacket dp = new DatagramPacket(packet, packet.length);
DatagramSocket ds = null;
try {
ds = new DatagramSocket(udp);
ds.receive(dp);
//...
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ds != null) {
ds.close();
}
}
return null;
}
}
I send UDP data to computer from Android device.
Computer immediately sends response as UDP packet.
I save information to my log file on SD.
And I see, that my app stays on the line "ds.receive(dp);" and does not run after it.
I've tested on the Android device against a program on computer.
As I understand it is tricky to receive UDP packets on Emulator.
I could not do it.
Redirect does not work for me as it is described here
Another important issue is to receive all packets, that were sent to the device. Lossless. How to modify the code for that?
Please help! Thanks!
put your receive inside a while(true) loop. When you receive a packet call an if (pkg_received){break;}... or whatever you want to do...
The problem is that you are probably only be receiving one package and you are getting timeout before receiving it.
Code edited and not tested
while(true)
{
byte[] message = new byte[60*1024];
DatagramPacket recv_packet = new DatagramPacket(message, message.length);
try {
socket.receive(recv_packet);
} catch (IOException e) {
e.printStackTrace();
}
Log.d("UDP", "S: Receiving...listening on port " + recv_packet.getPort() );
String rec_str;
rec_str=new String(recv_packet.getData)
Log.d("PACKAGE LENGTH",Integer.toString(recv_packet.getLength()));
}
I have an UDP server wrote in C langage which broadcasts paquets over my LAN every 5seconds, on port 3001.
i'm creating an android application as UDP client, which is listening on port 3001 (in the AsyncTask thread) and it's running until the receive() method, no data seems to be detected on this port.
Here is my code :
private class ConnectionTask extends AsyncTask<Void, Integer, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... arg0) {
String receivedString = "";
byte[] receiveData = new byte[1024];
DatagramSocket clientSocket;
try {
while(true){
clientSocket = new DatagramSocket(5000);
DatagramPacket receivePacket = new DatagramPacket(receiveData,
receiveData.length);
clientSocket.receive(receivePacket);
receivedString = new String(receivePacket.getData());
}
} catch (SocketException e) {
Log.v("SocketExceptionOccured", e.toString());
e.printStackTrace();
//clientSocket.close();
} catch (IOException e) {
Log.v("IOExceptionOccured", e.toString());
e.printStackTrace();
//clientSocket.close();
}
Toast.makeText(getBaseContext(), receivedString, Toast.LENGTH_LONG)
.show();
return null;
}
}
I test my code with my own device for debug, with USB cable.
I've tested my server with a simple UDP client (in C) running on my computer, and the communication is ok.
I don't know why this code doesn't work. Has someone an idea ?
Thanks,
You're never leaving the while loop. You're message is probably received, and after it, the loop causes the datagramsocket to listen again.
Don't create and close the socket every time around the loop. Create it first and close it afterwards. At present there are windows of time during which the socket doesn't exist, so datagrams to it are dropped: also, all queued datagrams are dropped every time you close it.
I had this same problem. You need to add permissions in the android manifest
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
Also enable broadcasts in the socket.
clientSocket.setBroadcast(true);
Like everyone else before me mentioned, your code also never leaves the while loop, so it never goes to the the line where the toast is displayed.Remember that you CANNOT show Toast messages from doInBackground as this is accessing the UI Thread, you can only do so from the postExecute and preExecute functions. This will cause your application to crash. To check the data you receive you can either debug it or log it.
Your final doInBackground should be something like this
#Override
protected Void doInBackground(Void... arg0) {
String receivedString = "";
byte[] receiveData = new byte[1024];
DatagramSocket clientSocket;
try {
while(true){
clientSocket = new DatagramSocket(5000);
DatagramPacket receivePacket = new DatagramPacket(receiveData,
receiveData.length);
clientSocket.setBroadcast(true);
clientSocket.receive(receivePacket);
receivedString = new String(receivePacket.getData());
Log.i("Received String= "+receivedString);
}
} catch (SocketException e) {
Log.v("SocketExceptionOccured", e.toString());
e.printStackTrace();
//clientSocket.close();
} catch (IOException e) {
Log.v("IOExceptionOccured", e.toString());
e.printStackTrace();
//clientSocket.close();
} finally{
if(clientSocket!=null){
clientSocket.close();
}
}
return null;
}
Now when you check your logs, you should be able to see the value of the string received.
WiBro, which is used as a server module and client Nexus Galaxy ICS.
Both machines are 3g UDP communication.
The server will return only the received data has been implemented.
dSocket.send (sendPacket) is a smooth communication.
However, we have a problem.
dSocket.receive (recvPacket) does not receive the data.
The server sends the packet is wrong? If the client receives the packet is wrong?
The server sends data but, telecom equipment is taken to preserve the situation?
When only sending a packet, the client has not a problem.
but after receive code implementation, the client has a problem.
private class ClientThread implements Runnable{
#SuppressWarnings("finally")
#Override
public void run() {
// TODO Auto-generated method stub
DatagramSocket dSocket = null;
try{
InetAddress serverAddr = InetAddress.getByName(serverIpAddress.toString());
Log.d(TAG, "Connecting");
Log.d(TAG, "IP :::: " + serverAddr.toString());
dSocket = new DatagramSocket(SERVERPORT);
dSocket.setSoTimeout(5000);
byte[] arr_RecvPacket = new byte[1024];
connected = true;
while(connected){
try{
Log.d(TAG, "Sending Command :::: ( " + String.valueOf(i));
String strPacket = "Hey Server ( " + String.valueOf(i);
byte[] arr_Packet = strPacket.getBytes();
sendPacket = new DatagramPacket(arr_Packet, arr_Packet.length, serverAddr, SERVERPORT);
dSocket.send(sendPacket);
Log.d(TAG, "C:Send");
i++;
Log.d(TAG, "C:Make Recv Packet....");
recvPacket = new DatagramPacket(arr_RecvPacket, arr_RecvPacket.length);
Log.d(TAG, "C:Recving...");
dSocket.receive(recvPacket);
handler.sendEmptyMessage(0x01);
Thread.sleep(4000);
}catch(Exception e){
e.printStackTrace();
Log.d(TAG, "S:Error");
}
}
Log.d(TAG, "S:DataSocket close");
dSocket.close();
}catch(Exception e){
Log.d(TAG, "C:Error");
e.printStackTrace();
connected = false;
}finally{
connected = false;
if(dSocket != null){
dSocket.close();
}
return;
}
}
}
The server sends the packet is wrong?
Could be. Hard to say without seeing it. It should send the reply back to the IP:port embedded in the incoming datagram. Easiest way to do that is to reuse it, just change the data.
the client receives the packet is wrong?
It looks OK.
The server sends data but, telecom equipment is taken
to preserve the situation?
I don't know what this means.