Is there a way to ping a host (standard Android or via NDK implementation), and get detailed info on the response? (time, ttl, lost packages, etc..)
I was thinking of some open source app that has this feature but can't find any...
Thanks
Afaik, sending ICMP ECHO requests needs root (i.e. the app that does it needs to be setuid) - and that's not currently possible in "stock" Android (hell, even the InetAddress#isReachable() method in Android is a joke that doesn't work according to spec).
A very basic example using /usr/bin/ping & Process - reading the ping results, using an AsyncTask:
public class PingActivity extends Activity {
PingTask mTask;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
#Override
protected void onResume() {
super.onResume();
mTask = new PingTask();
// Ping the host "android.com"
mTask.execute("android.com");
}
#Override
protected void onPause() {
super.onPause();
mTask.stop();
}
class PingTask extends AsyncTask<String, Void, Void> {
PipedOutputStream mPOut;
PipedInputStream mPIn;
LineNumberReader mReader;
Process mProcess;
TextView mText = (TextView) findViewById(R.id.text);
#Override
protected void onPreExecute() {
mPOut = new PipedOutputStream();
try {
mPIn = new PipedInputStream(mPOut);
mReader = new LineNumberReader(new InputStreamReader(mPIn));
} catch (IOException e) {
cancel(true);
}
}
public void stop() {
Process p = mProcess;
if (p != null) {
p.destroy();
}
cancel(true);
}
#Override
protected Void doInBackground(String... params) {
try {
mProcess = new ProcessBuilder()
.command("/system/bin/ping", params[0])
.redirectErrorStream(true)
.start();
try {
InputStream in = mProcess.getInputStream();
OutputStream out = mProcess.getOutputStream();
byte[] buffer = new byte[1024];
int count;
// in -> buffer -> mPOut -> mReader -> 1 line of ping information to parse
while ((count = in.read(buffer)) != -1) {
mPOut.write(buffer, 0, count);
publishProgress();
}
out.close();
in.close();
mPOut.close();
mPIn.close();
} finally {
mProcess.destroy();
mProcess = null;
}
} catch (IOException e) {
}
return null;
}
#Override
protected void onProgressUpdate(Void... values) {
try {
// Is a line ready to read from the "ping" command?
while (mReader.ready()) {
// This just displays the output, you should typically parse it I guess.
mText.setText(mReader.readLine());
}
} catch (IOException t) {
}
}
}
}
I found a way to execute ping command without root.
Spawns a 'sh' process first, and then execute 'ping' in that shell, the code:
p = new ProcessBuilder("sh").redirectErrorStream(true).start();
DataOutputStream os = new DataOutputStream(p.getOutputStream());
os.writeBytes("ping -c 10 " + host + '\n');
os.flush();
// Close the terminal
os.writeBytes("exit\n");
os.flush();
// read ping replys
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
It works fine on my HTC device with CyanogenMod 7.1.0 (Android 2.3.7)
Related
To run the executable and get the real-time output I'm using the following code (with String[] command = new String[]{"/a.out"};):
public static void execute(String... command) {
try {
ProcessBuilder builder = new ProcessBuilder(command);
builder.redirectErrorStream(true);
final Process proc = builder.start();
new Thread(new Runnable() {
public void run() {
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null) {
EventBus.getDefault().post(new MessageEvent(line+"\n"));
}
} catch (Exception e) {
// TODO
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
// ignore
}
}
}
}
}).start();
} catch (IOException e) {
e.printStackTrace();
}
}
The command should be executed inside a service:
public class Service extends IntentService {
...
#Override
protected void onHandleIntent(Intent intent) {
String[] command = new String[]{"/a.out"};
Class.execute(command);
}
}
But I only get one line as an output, nothing more, but it should be hundreds of them. I already tried it on my computer by replacing EventBus.getDefault().post(new MessageEvent(line+"\n")); with System.out.println(line); and it works just fine.
Additional information: Subscriber handles EventBus through:
#Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
tv.append(event.getMessage());
}
#Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
#Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
And tv is a TextView: TextView tv = (TextView)findViewById(R.id.TextView);
This structure was tested with a simple method, which in the following shown. It updated the TextView and there was more than one line passed to the TextView. So I guess it must be something inside my execution method.
public static void test() {
for(int i = 0; i<500000; i++)
EventBus.getDefault().post(new MessageEvent(i+"\n"));
}
Why does the EventBus only passes one line? What can I change to get the expected result?
Edit: Changing onMessageEvent() to:
public void onMessageEvent(MessageEvent event) {
Log.i("Activity",event.getMessage());
}
Also just one line.
Tested it with another executable, now it works just fine, any idea why it works now?
Is it passing only one line? It looks like your appending all the text into a single line by doing this -> tv.append(event.getMessage());
In your onMessageEvent() method try to System.out.println(event.getMessage()); to assert if the problem is really from EventBus.
this is the class for reading json string from web
{
public class JSONmethod extends AsyncTask<String,String,String>
{
public String result_string;
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
BufferedReader reader = null;
HttpURLConnection connection = null;
StringBuffer buffer;
try {
URL url;
url = new URL(params[0]);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
String line= "";
buffer = new StringBuffer();
while ((line = reader.readLine())!= null)
{
buffer.append(line);
}
return buffer.toString();
}
catch(MalformedURLException e)
{
e.printStackTrace();
}
catch(IOException e)
{
e.printStackTrace();
}
finally
{
if (connection != null) {
connection.disconnect();
}
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
result_string=result;
}
public String result_string_josn()
{
return result_string;
}
}
method "result_string_json()" return null string
i want to use this class frequntly for reading the json string from the web
so i made this method for return string which will returns from onPostExecute
this is the class where i want that value which is generate in post execute through method or anything else
simple.java
package com.bhatti.bis;
import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;
public class simple extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple);
JSONmethod j = new JSONmethod();
j.execute("here is json string");
Toast.makeText(this,j.result_string_josn(),Toast.LENGTH_LONG).show();
}
}
Use EventBus library. It's very easy to use and will perfectly fix your problem:
First create a simple class for your Event:
public class MyEvent{
private String data;
public MyEvent(String data) {
this.data = data;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
Then in your Activity or wherever, register and unregister the EventBus, as explained in the docs.
Now post the appropriate event:
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
EventBus.getDefault().post(new MyEvent(jsonArray.toString()));
}
All that's left for you to do is to listen for that event wherever you want (in another Activity, Fragment, Service - that's what makes EventBus great):
#Subscribe
public void onMyEvent(MyEvent myEvent){
String data = myEvent.getData();
//do whatever you wish with the text (e.g. make a toast, write it somewhere)
}
Async Task is asynchronous task, please read https://en.wikipedia.org/wiki/Asynchrony_%28computer_programming%29
Remove Toast just after :
JSONmethod j = new JSONmethod();
j.execute("here is json string");
And put it in onPostExecute :
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
Toast.makeText(this,result,Toast.LENGTH_LONG).show();
}
Android handles input events/tasks with a single User Interface (UI) thread and the thread is called Main thread. Main thread cannot handle concurrent operations as it handles only one event/operation at a time.For detail read this tutorials
JSONmethod jSONmethod = new JSONmethod();
jSONmethod.execute("Your json string");
public class JSONmethod extends AsyncTask<String,String,String>
{
public String result_string;
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
BufferedReader reader = null;
HttpURLConnection connection = null;
StringBuffer buffer;
try {
URL url;
url = new URL(params[0]);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
String line= "";
buffer = new StringBuffer();
while ((line = reader.readLine())!= null)
{
buffer.append(line);
}
return buffer.toString();
}
catch(MalformedURLException e)
{
e.printStackTrace();
}
catch(IOException e)
{
e.printStackTrace();
}
finally
{
if (connection != null) {
connection.disconnect();
}
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
Log.d("JSONmethod","result = "+result);
}
}
I'm apologise for my english.
I use the following piece of code to download a file from ftp host to Tablet. When I use Wi-Fi everything works well. But when I try to download a file using the mobile Internet, the download stops, but not always, sometimes finishes normally. I've found that stop is always going on "retrieveFile" or "logout", the program comes to these commands and no going further, and simply stands, the icon of data transfer does not blink, stops occur randomly. I tried to use different mobile operators, but there is no difference. What could be the reason?
And another question, but It is not so important, I've not found how to get the file size, and used my decision, maybe there is another way to get the file size ?
private void downloadFile(final String url, final String Message, final String Message2, final Uri uri) {
final ProgressDialog progressDialog = new ProgressDialog(this);
new AsyncTask() {
private Exception m_error = null;
#Override
protected void onPreExecute() {
progressDialog.setMessage(Message);
progressDialog.setCancelable(true);
progressDialog.setMax(100);
progressDialog
.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.show();
}
#Override
protected File doInBackground(String... params) {
FileOutputStream fos = null;
File file = null;
FTPClient client = null;
try{
client = new FTPClient();
client.connect(ftp_host,Integer.parseInt(ftp_port));
client.login(ftp_user, ftp_password);
client.enterLocalPassiveMode();
client.setFileType(FTP.BINARY_FILE_TYPE);
String stat = "";
if (url.equals("MobiTrade.apk")){
client.changeWorkingDirectory("/var/srv/home/user/mobitrade/update/");}
file = new File(Environment.getExternalStorageDirectory(),
"/MobiTrade/update/MobiTrade.apk");}
stat = client.getStatus("/var/srv/home/user/mobitrade/update/MobiTrade.apk");
else {
client.changeWorkingDirectory("/var/srv/home/user/mobitrade/"+number+"/out/");
file = new File(Environment.getExternalStorageDirectory(),
"/MobiTrade/in/"+url);
if (url.equals("message.csv")) file.delete();
stat = client.getStatus("/var/srv/home/user/mobitrade/"+number+"/out/"+url);
}
final Integer FileSize;
if (stat.length() >= 64) {
stat = stat.substring(49,64);
stat = stat.trim();
FileSize = Integer.parseInt(stat);
}
else {
FileSize = 0;
}
fos = new FileOutputStream(file);
CountingOutputStream cos = new CountingOutputStream(fos){
protected void beforeWrite(int n){
super.beforeWrite(n);
publishProgress(getCount(), FileSize);
}
};
if (url.equals("MobiTrade.apk")){
client.retrieveFile("/var/srv/home/user/mobitrade/update/MobiTrade.apk", cos);
}
else {
client.retrieveFile("/var/srv/home/user/mobitrade/"+number+"/out/"+url, cos);
}
if (url.equals("message.csv")){
client.deleteFile("/var/srv/home/user/mobitrade/"+number+"/out/"+url);
}
client.logout();
}
catch (Exception e){
e.printStackTrace();
}
finally{
try{
if (fos != null) fos.close();
if (client.isConnected()) {
client.disconnect();
}
}
catch (IOException e){
e.printStackTrace();
}
}
return file;
}
protected void onProgressUpdate(Integer... values) {
progressDialog
.setProgress((int) ((values[0] / (float) values[1]) * 100));
};
#Override
protected void onPostExecute(File result) {
if (m_error != null) {
m_error.printStackTrace();
return;
}
progressDialog.hide();
if (url.equals("settings.csv"))
ProcessSettings(url);
else if (url.equals("MobiTrade.apk"))
ProcessUpdate();
else
ProcessData(url, Message2, uri);
}
}.execute(url);
}
Any help would be appreciable.
I can't seem to get runtime.exec working in my android app. I've tried it with a host of shell utilities, here's the code I'm using:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
filesPrinter = (Button) findViewById(R.id.print_files);
filesPrinter.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
try {
Process proc = Runtime.getRuntime().exec("ls");
out = new BufferedWriter(new OutputStreamWriter(proc.getOutputStream()));
in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line;
while((line = in.readLine()) != null) {
System.out.println(line);
}
System.out.println("Done reading");
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
I don't get an error, but also do not get anything in logcat.
The problem ended up being a bug with the eclipse logcat. Using adb logcat, I could see everything that was supposed to be outputted. For some reason, logcat on eclipse showed that it was connected but was not receiving any application level output from the emulator.
Maybe your current working directory (which is what ls scans without any parameters) simply contains no files. Try providing a path as a command argument.
Think you're missing a proc.waitFor()....
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
filesPrinter = (Button) findViewById(R.id.print_files);
filesPrinter.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
try {
Process proc = Runtime.getRuntime().exec("ls");
out = new BufferedWriter(new OutputStreamWriter(proc.getOutputStream()));
in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line;
while((line = in.readLine()) != null) {
System.out.println(line);
}
System.out.println("Done reading");
//
proc.waitFor(); // THIS!!!
//
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
I have got huge problem with my Android app and I would like to ask you for help.
I am currently writing Android Clietn-Server app using sockets. I have found lots of tutorils on the Internet and from them I have created basics for my project. However, all tutorials are only for one message send and that's all. I need to send more of them so I've been trying to modify it.
This are code fragments responsible for server and client. The rest is not important at this time.
Server:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
serverStatus = (TextView) findViewById(R.id.server_status);
recivedMsg = (TextView)findViewById(R.id.rec_msg);
SERVERIP = getLocalIpAddress();
Thread fst = new Thread(new ServerThread());
fst.start();
}
public class ServerThread implements Runnable {
public void run() {
try {
if (SERVERIP != null) {
handler.post(new Runnable() {
#Override
public void run() {
serverStatus.setText("Listening on IP: " + SERVERIP);
}
});
serverSocket = new ServerSocket(SERVERPORT);
while (true) {
// listen for incoming clients
Socket client = serverSocket.accept();
handler.post(new Runnable() {
#Override
public void run() {
serverStatus.setText("Connected." + System.getProperty("line.separator"));
}
});
try {
line = null;
while (connected) {
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
if((line = in.readLine())!=null)
{
Log.d("ServerActivity", line);
handler.post(new Runnable() {
#Override
public void run() {
if(recivedMsg.equals("CLOSE"))
{
recivedMsg.append("CLOSE socket");
connected = false;
}
else
{
recivedMsg.append("MSG: " + line + System.getProperty("line.separator"));
}
// do whatever you want to the front end
// this is where you can be creative
}
});
}
else
{
recivedMsg.append("empty" + System.getProperty("line.separator"));
}
}
break;
} catch (Exception e) {
handler.post(new Runnable() {
#Override
public void run() {
serverStatus.setText("Oops. Connection interrupted. Please reconnect your phones.");
}
});
e.printStackTrace();
}
}
} else {
handler.post(new Runnable() {
#Override
public void run() {
serverStatus.setText("Couldn't detect internet connection.");
}
});
}
} catch (Exception e) {
handler.post(new Runnable() {
#Override
public void run() {
serverStatus.setText("Error");
}
});
e.printStackTrace();
}
}
}
Client
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
serverIp = (EditText) findViewById(R.id.server_ip);
connectPhones = (Button) findViewById(R.id.connect_phones);
sendField = (EditText) findViewById(R.id.send_field);
sendMsg = (Button) findViewById(R.id.msg_send);
connectPhones.setOnClickListener(connectListener);
sendMsg.setOnClickListener(sendMessage);
}
#Override
protected void onStop() {
super.onStop();
try {
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
//send output msg
String outMsg = "CLOSE";
out.write(outMsg);
out.flush();
// make sure you close the socket upon exiting
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private OnClickListener connectListener = new OnClickListener() {
#Override
public void onClick(View v) {
serverIpAddress = serverIp.getText().toString();
runTcpConnection();
sendMessageToServer("Msg");
}
};
private OnClickListener sendMessage = new OnClickListener() {
#Override
public void onClick(View v) {
sendMessageToServer(sendField.getText().toString());
}
};
private void runTcpConnection() {
try {
s = new Socket(serverIpAddress, SERVERPORT);
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
//send output msg
String outMsg = "TCP connecting to " + SERVERPORT + System.getProperty("line.separator");
out.write(outMsg);
out.flush();
Log.i("TcpClient", "sent: " + outMsg);
SystemClock.sleep(10);
s.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
};
public void sendMessageToServer(String str) {
try {
s = new Socket(serverIpAddress, SERVERPORT);
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
//send output msg
String outMsg = str + System.getProperty("line.separator");
out.write(outMsg);
out.flush();
Log.i("TcpClient", "sent: " + outMsg);
s.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.d("", "hello222");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.d("", "hello4333");
}
}
For now devices connect correctly. Moreover They are sending the first connection messages (those in OnClickListener connectListener). The problem is that when I am trying to send another message using sendMessageToServer it is impossible. Those messages shows only after client activity is destroyed.
Very interesting is that without SystemClock.sleep(10); listener runTcpConnection() behave strange. Only 'Connected.' displays on server.
Can someone tell me what I have to do to be able to send messages normally?
EDIT:
This are things that I have found:
If I am at the connection sending more messages than all are empty (null) and after the second one connection error shows - please reconnect phones
If I am at the connection sending more messages without s.close line in sendMessageToServer only one message is passing through. No error is displayed after it.
The message form runTcpConnection shows always (except when in this function is no SystemClock.sleep(10))
Hope it will help someone to diagnose my error.
As I see, you create a new socket whenever user click button send, right? I recommend you should init it only one time when user click connect, then you use it in send click event ( because this is TCP, you will disconnect to server if you create new instance of socket)
So, you should remove these lines in sendMessageToServer :
s = new Socket(serverIpAddress, SERVERPORT);
s.close();
and this line in runTcpConnection
s.close();
Socket should close whenever you don't want communicate with the server (onstop is an example, or when change activity...)
Also you should create only one instance of BufferedWriter too.
Hope this help.