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()));
}
Related
I'm currently runing a server on Eclipse(local IP 192.168.1.255, listening to port 4567). A client can connect trought sockets and send messages, that will be printed on the terminal by the server.
Part of the server code is the following:
System.out.println("Client connected: " + clientName);
String line;
while (true){
line = in.nextLine();
System.out.println("STRING RECEIVED: " + line + " FROM " + clientName);
}
where in is the input stream of the client socket.
Part of client code, instead, is:
while(true) {
System.out.print("\nEnter your input: ");
line = stdin.next();
socketOut.println(line);
socketOut.flush();
}
So, in example, a possible output on server terminal with two clients connected is the following:
Client connected: Socket[addr=/192.168.1.225,port=54852,localport=4567]
STRING RECEIVED: Hello FROM Socket[addr=/192.168.1.225,port=54852,localport=4567]
STRING RECEIVED: World FROM Socket[addr=/192.168.1.225,port=54852,localport=4567]
Client connected: Socket[addr=/192.168.1.225,port=54945,localport=4567]
STRING RECEIVED: Hello2 FROM Socket[addr=/192.168.1.225,port=54945,localport=4567]
Everything works well, so i'm now trying to access server trough sockets on a simple app developed on Android Studio. The code is:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new BackgroundTask().execute();
}
private class BackgroundTask extends AsyncTask {
#Override
protected Object doInBackground(Object[] params) {
try {
Socket socket = new Socket("10.0.2.2", 4567);
PrintWriter out = new PrintWriter(socket.getOutputStream());
out.println(new String("Hi from Android!"));
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
}
But the output is just
Client connected: Socket[addr=/192.168.1.225,port=55001,localport=4567]
and nothing else.
Any advice about the println doesn't send anything? The program works perfectly on Eclipse on both client/server side, so i guess the problem is on Android. Also, i enabled the Android network permissions, so the connection should work.
Thanks in advance to everybody.
EDIT: solved, i just changed Android client code to:
try {
Socket socket = new Socket("10.0.2.2", 4567);
if (socket.isConnected()) {
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())), true);
String line = new String("Hi from Android!");
out.println(line);
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
You need to either flush the PrintWriter or construct it to auto-flush. It doesn't by default.
I have created an application to Android and Microsoft Hololens, where it is possible to send some GPS-data with bluetooth from an Android-phone to a Hololens (with Bluetooth LE Advertiser) and that works allright. But when I am trying to send other data from Hololens to Android, I have a problem that Android-phone can't discover Hololens, although these devices are paired. Is it even possible to send data from Hololens with bluetooth, or is there only something wrong in my code? Does Bluetooth LE Advertising support two-way data transfering?
I am guessing you have a BluetoothConnected thread in your android app with an InputStream (mine is mmInStream). Try using this as your 'run' function in the thread:
public void run() {
System.out.println("BT THREAD RUNNING");
mmBuffer = new byte[1024];
int numBytes; // bytes returned from read()
InputStreamReader mmInStreamReader = new InputStreamReader(mmInStream);
BufferedReader mmReader = new BufferedReader(mmInStreamReader);
// Keep listening to the InputStream until an exception occurs.
while (true) {
try {
// Read from the InputStream.
Thread.sleep(100);
String s = mmReader.readLine();
Thread.sleep(100);
//Static class that handles the response
BluetoothCommunications.responseHandler(s);
} catch (IOException e) {
System.out.println("Input stream was disconnected" + e);
main.disconnected();
break;
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
UPDATED:
I get crash in this Android UDP server example:
//------------------------------------------------------------
public class AsyncReceiveUdp2 extends AsyncTask<String, Void, Boolean> {
#Override
protected Boolean doInBackground(String... f_url) {
int udp=111;
String txt="";
byte[] packet = new byte[2000];
DatagramPacket dp = new DatagramPacket(packet, packet.length);
DatagramSocket ds = null;
try {
ds = new DatagramSocket(udp);
ds.setSoTimeout(10000);
printLog("Ready");
ds.receive(dp);
printLog("Received");
...
} catch (SocketException e) {
printLog("Error1");
e.printStackTrace();
} catch (IOException e) {
printLog("Error2");
e.printStackTrace();
} finally {
if (ds != null) {
ds.close();
}
}
return null;
}
}
I get my "error2" message.
The reason is "java.net.SocketTimeoutException".
It happens after 10 seconds.
But I sent UDP packet from another computer.
Hmm, I don't understand how it works....
Any ideas please!
Sorry for extra line, the site said that my post is mostly code
Sorry for extra line, the site said that my post is mostly code
Sorry for extra line, the site said that my post is mostly code
You cannot run network threads on the UI thread, Android policy forbids it. Make a new thread or use AsyncTask
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;
}
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.