I am running a server which writes a simple Welcome message to a new Client upon Successful connection!
Now I am sure of it that my android device connects to the server but I am unable to receive the welcome text that the server sends.
I am new to socket programming and I am looking for a unified solution to this.
I will paste my code which has a successful outputStream snippet and gets the android connected to the server. I ll leave the InputStream section black, since I need the solution for that!
private ArrayBlockingQueue<Integer> mQueue = new ArrayBlockingQueue<Integer>(100);
private AtomicBoolean mStop = new AtomicBoolean(false);
private OutputStream mOutputStream = null;
private InputStream mInputStream = null;
private Socket mSocket = null;
private static Thread sNetworkThread = null;
private final Runnable mNetworkRunnable = new Runnable() {
log("starting network thread");
String encoding = "UTF-8";
String output="";
#Override
public void run() {
log("starting network thread");
try {
mSocket = new Socket(ARDUINO_IP_ADDRESS, PORT);
mOutputStream = mSocket.getOutputStream();
mInputStream = mSocket.getInputStream();
} catch (UnknownHostException e1) {
e1.printStackTrace();
mStop.set(true);
} catch (IOException e1) {
e1.printStackTrace();
mStop.set(true);
}
mQueue.clear(); // we only want new values
//Output Stream
try {
while(!mStop.get()){
int val = mQueue.take();
if(val >= 0){
log("sending value "+val);
mOutputStream.write((val+"\n").getBytes());
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally{
try {
mStop.set(true);
if(mOutputStream != null) mOutputStream.close();
if(mSocket != null) mSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//InputStream
try
{
//Call method to read inputStream
output = readFully(mInputStream,encoding);
} catch (IOException e) {
e.printStackTrace();
}
Toast.makeText(getApplicationContext(),"Server Message"+output, Toast.LENGTH_SHORT).show();
log("returning from network thread");
sNetworkThread = null;
}
};
Well I added two methods to achieve the inputStream by calling it from the thread. The methods are as follows.
public String readFully(InputStream inputStream, String encoding)
throws IOException {
return new String(readFully(inputStream), encoding);
}
private byte[] readFully(InputStream inputStream)
throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length = 0;
while ((length = inputStream.read(buffer)) != -1) {
baos.write(buffer, 0, length);
}
return baos.toByteArray();
}
** The Server returns a String - "Welcome New User"
Well I hv used putty in RAW mode to coonect to the server and it works fine.
StackTrace Logs:
03-02 16:46:22.790 11813-12339/com.example.bonny.myapplication D/>==< ArduinoYun >==<﹕ starting network thread
03-02 16:46:22.790 11813-12339/com.example.bonny.myapplication D/libc﹕ [NET] getaddrinfo hn 9, servname NULL, ai_family 0+
03-02 16:46:22.790 11813-12339/com.example.bonny.myapplication D/libc﹕ [NET] ht 0x31302e302e302e
03-02 16:46:22.790 11813-12339/com.example.bonny.myapplication D/libc﹕ [NET] getaddrinfo-exit SUCCESS
I need to integrate the inputStream on this thread.
P.S. OutputStream works smoothly from this code!
You need to read one line. Your present code tries to read everything until end of stream, whuch only happens when the peer closes the connection.
public String convertStreamToString(java.io.InputStream is)
{
BufferedReader br = null;
StringBuilder sb = new StringBuilder();
String line;
try
{
br = new BufferedReader(new InputStreamReader(is));
while ((line = br.readLine()) != null)
{
sb.append(line);
}
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
if (br != null)
{
try
{
br.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
return sb.toString();
}
Above code might help you in converting InputStream into String.
I hope this will help you.
Related
I'm trying to execute this command from the application emulator terminal (you can find it in google play) in this app i write su and press enter, so write:
screenrecord --time-limit 10 /sdcard/MyVideo.mp4
and press again enter and start the recording of the screen using the new function of android kitkat.
so, i try to execute the same code from java using this:
Process su = Runtime.getRuntime().exec("su");
Process execute = Runtime.getRuntime().exec("screenrecord --time-limit 10 /sdcard/MyVideo.mp4");
But don't work because the file is not created. obviously i'm running on a rooted device with android kitkat installed. where is the problem? how can i solve? because from terminal emulator works and in Java not?
You should grab the standard input of the su process just launched and write down the command there, otherwise you are running the commands with the current UID.
Try something like this:
try{
Process su = Runtime.getRuntime().exec("su");
DataOutputStream outputStream = new DataOutputStream(su.getOutputStream());
outputStream.writeBytes("screenrecord --time-limit 10 /sdcard/MyVideo.mp4\n");
outputStream.flush();
outputStream.writeBytes("exit\n");
outputStream.flush();
su.waitFor();
}catch(IOException e){
throw new Exception(e);
}catch(InterruptedException e){
throw new Exception(e);
}
A modification of the code by #CarloCannas:
public static void sudo(String...strings) {
try{
Process su = Runtime.getRuntime().exec("su");
DataOutputStream outputStream = new DataOutputStream(su.getOutputStream());
for (String s : strings) {
outputStream.writeBytes(s+"\n");
outputStream.flush();
}
outputStream.writeBytes("exit\n");
outputStream.flush();
try {
su.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
outputStream.close();
}catch(IOException e){
e.printStackTrace();
}
}
(You are welcome to find a better place for outputStream.close())
Usage example:
private static void suMkdirs(String path) {
if (!new File(path).isDirectory()) {
sudo("mkdir -p "+path);
}
}
Update:
To get the result (the output to stdout), use:
public static String sudoForResult(String...strings) {
String res = "";
DataOutputStream outputStream = null;
InputStream response = null;
try{
Process su = Runtime.getRuntime().exec("su");
outputStream = new DataOutputStream(su.getOutputStream());
response = su.getInputStream();
for (String s : strings) {
outputStream.writeBytes(s+"\n");
outputStream.flush();
}
outputStream.writeBytes("exit\n");
outputStream.flush();
try {
su.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
res = readFully(response);
} catch (IOException e){
e.printStackTrace();
} finally {
Closer.closeSilently(outputStream, response);
}
return res;
}
public static String readFully(InputStream is) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length = 0;
while ((length = is.read(buffer)) != -1) {
baos.write(buffer, 0, length);
}
return baos.toString("UTF-8");
}
The utility to silently close a number of Closeables (Soсket may be no Closeable) is:
public class Closer {
// closeAll()
public static void closeSilently(Object... xs) {
// Note: on Android API levels prior to 19 Socket does not implement Closeable
for (Object x : xs) {
if (x != null) {
try {
Log.d("closing: "+x);
if (x instanceof Closeable) {
((Closeable)x).close();
} else if (x instanceof Socket) {
((Socket)x).close();
} else if (x instanceof DatagramSocket) {
((DatagramSocket)x).close();
} else {
Log.d("cannot close: "+x);
throw new RuntimeException("cannot close "+x);
}
} catch (Throwable e) {
Log.x(e);
}
}
}
}
}
Process p;
StringBuffer output = new StringBuffer();
try {
p = Runtime.getRuntime().exec(params[0]);
BufferedReader reader = new BufferedReader(
new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
p.waitFor();
}
}
catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
String response = output.toString();
return response;
Late reply, but it will benefit someone. You can use the sh command in the exec() method.
Here is my example:
try {
File workingDirectory = new File(getApplicationContext().getFilesDir().getPath());
Process shProcess = Runtime.getRuntime().exec("sh", null, workingDirectory);
try{
PrintWriter outputExec = new PrintWriter(new OutputStreamWriter(shProcess.getOutputStream()));
outputExec.println("PATH=$PATH:/data/data/com.bokili.server.nginx/files;export LD_LIBRARY_PATH=/data/data/com.bokili.server.nginx/files;nginx;exit;");
outputExec.flush();
} catch(Exception ignored){ }
shProcess.waitFor();
} catch (IOException ignored) {
} catch (InterruptedException e) {
try{ Thread.currentThread().interrupt(); }catch(Exception ignored){}
} catch (Exception ignored) { }
What have I done with this?
First I call the shell, then I change (set) the necessary environments in it, and finally I start my nginx with it.
This works on unrooted devices too.
Greetings.
It has been days I am struggling with this problem. I want to create a local android server to let other devices download a file in LAN. So far i have created a socket server that writes a pdf file along with header on output stream, but it is not working. When url is hit on web browser almost 95% of the data is downloaded without any problem after that download fails, it shows network problem(In Google chrome).
Following is the code to create server:
class VideoStreamServer {
public void startServer() {
outFilePath = getActivity().getExternalFilesDir("/") + "/pdf.pdf";
outFile = new File(outFilePath);
Runnable videoStreamTask = new Runnable() {
#Override
public void run() {
try {
ServerSocket socket = new ServerSocket(port);
System.out.println("Waiting for client to connect.");
while (true) {
Socket client = socket.accept();
BufferedOutputStream os = new BufferedOutputStream(client.getOutputStream());
FileInputStream in = new FileInputStream(outFile);
BufferedInputStream inFromClient = new BufferedInputStream(client.getInputStream());
StringBuilder sb = new StringBuilder();
sb.append("HTTP/1.1 200 OK\r\n");
sb.append("Accept-Ranges: bytes\r\n");
sb.append("Connection: close\r\n");
sb.append("Content-Length: " + in.available() + "\r\n");
sb.append("Content-Disposition: attachment; filename=file.pdf\r\n");
sb.append("Content-Type: application/pdf \r\n");
sb.append("\r\n");
byte[] data = new byte[1024];
int length;
//inFromClient.read(data);
//System.out.println("request from client"+getStreamData(inFromClient));
System.out.println("Thread Started");
//System.setProperty("http.keepAlive", "false");
os.write(sb.toString().getBytes());
while ((length = in.read(data)) != -1) {
os.write(data, 0, length);
}
os.close();
client.close();
socket.close();
in.close();
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
};
Thread streamServer = new Thread(videoStreamTask);
streamServer.start();
}
}
Any help would be appreciated.
EDIT1
public String getStreamData(InputStream in) {
StringBuffer buffer = new StringBuffer();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line;
try {
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
} catch (IOException e) {
e.printStackTrace();
}
return buffer.toString();
}
I am developing a android wifi -chat application .
Bit of Info about my app :
->A device calls startserver() to act as a server ,another device calls start client() to act as a client
What works:
->A Client can successfully send the data for the first time to the client, but not again and again
->I need to call startserver() again on first device , so that client can send data again .
The startserver() calls this Async task ,the following is its DoinBackgroundMethod
protected String doInBackground(Void... params) {
ServerSocket serverSocket = null;
try {
while(true) {
serverSocket = new ServerSocket(PORT);
Socket client = serverSocket.accept();
StartMSG(client);
}
} catch (IOException e) {
return null;
} finally {
try {
chatclient.changeserverrunning(false);
if (serverSocket == null) {
} else {
serverSocket.close();
}
return null;
} catch (Exception e) {
}
}
//return null;
}
protected void StartMSG(Socket client){
try {
InputStream inputstream = client.getInputStream();
ObjectInputStream ois = new ObjectInputStream(inputstream);
Message m = null;
try {
m = (Message) ois.readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
if (m != null) {
if (m.gettype() == 1) {
final String my_msg = m.getMessage();//Toast msg afterwards
}
}catch (Exception e){
}
}
Client Side Code :
It is started when the client hits send button and calls start client method .in which It sets up the Ip values before and bundles them and calls the message sending part as a Intent Service called FileTransferService
Its code is (abstracted) :
protected void onHandleIntent(Intent intent) {
Context context = getApplicationContext();
if(socket==null){
socket = new Socket();
}
if (intent.getAction().equals(ACTION_SEND_FILE)) {
final String msg_type=intent.getExtras().getString(MESSAGE_TYPE);
String host = intent.getExtras().getString(EXTRAS_ADDRESS);
int port = intent.getExtras().getInt(EXTRAS_PORT);
try {
socket.bind(null);
socket.connect((new InetSocketAddress(host, port)), SOCKET_TIMEOUT);
Message m = (Message) intent.getExtras().getSerializable(MESSAGE_INTENT_STR);
final String my_message=m.getMessage();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(m);
oos.flush();
oos.close();
InputStream is = new ByteArrayInputStream(baos.toByteArray());
OutputStream stream = socket.getOutputStream();
ChatClient.copyFile(is, stream);
} catch (IOException e) {
} finally {
if (socket != null) {
if (socket.isConnected()) {
try {
//socket.close();
} catch (Exception e) {
// Give up
e.printStackTrace();
}
}
}
}
}
}
You should try https://github.com/tavendo/AutobahnAndroid and run the client from a service, from an asyntask it will always end up finishing.
The code is supposed to connect as a client to a TCP server, send a command and receive a response.
The code connects and sends the command but time-out-s at "socket.getInputStream()", even though the connected server receives the command and is supposed to respond (was checked using a TCP client program on the PC).
Here Is the Code for the task:
public class MyClientTask extends AsyncTask<Void, Void, Void> {
String dstAddress;
int dstPort;
String command;
String response = "";
MyClientTask(String addr, int port, String cmd){
dstAddress = addr;
dstPort = port;
command = cmd;
}
#Override
protected Void doInBackground(Void... arg0) {
Socket socket = null;
InputStream inputStream;
try {
socket = new Socket();
socket.connect(new InetSocketAddress(dstAddress, dstPort),2000);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(1024);
byte[] buffer = new byte[1024];
int bytesRead;
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);
out.println(command);
inputStream = socket.getInputStream();
socket.setSoTimeout(20000);
while ((bytesRead = inputStream.read(buffer)) != -1){
byteArrayOutputStream.write(buffer, 0, bytesRead);
response += byteArrayOutputStream.toString("UTF-8");
}
}catch (UnknownHostException e){
e.printStackTrace();
response = "UnknownHostException: " + e.toString();
} catch (IOException e) {
e.printStackTrace();
response = "IOException: " + e.toString();
} catch (Throwable e) {
e.printStackTrace();
response = "Throwable: " + e.toString();
}finally{
if(socket != null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
#Override
protected void onPostExecute(Void result) {
textResponse.setText(response);
super.onPostExecute(result);
}
}//MyClientTask
You're reading the response until end of stream. End of stream won't occur until the peer closes the connection. You got a read timeout: ergo, probably, he didn't close the connection. Or else your timeout is too short. Two seconds isn't much.
You need a proper way of reading the response, or of dealing with the parts as they arrive.
I was previously using HttpClient and BasicNameValuePairs, for some reason i have to shift to HttpUrlConnection.
Hence this code, to make a HttpPost request with certain parameters:
public class MConnections {
static String BaseURL = "http://www.xxxxxxxxx.com";
static String charset = "UTF-8";
private static String result;
private static StringBuilder sb;
private static List<String> cookies = new ArrayList<String>();
public static String PostData(String url, String sa[][]) {
HttpURLConnection connection = null;
try {
connection = (HttpURLConnection) new URL(BaseURL + url)
.openConnection();
} catch (MalformedURLException e1) {
} catch (IOException e1) {
}
cookies = connection.getHeaderFields().get("Set-Cookie");
try{
connection.setDoOutput(true); // Triggers POST.
connection.setRequestProperty("Accept-Charset", charset);
connection.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded;charset=" + charset);
}catch (Exception e) {
//Here i get Exception that "java.lang.IllegalStateException: Already connected"
}
OutputStream output = null;
String query = "";
int n = sa.length;
for (int i = 0; i < n; i++) {
try {
query = query + sa[i][0] + "="
+ URLEncoder.encode(sa[i][1], "UTF-8");
} catch (UnsupportedEncodingException e) {
}
}
try {
output = connection.getOutputStream();
output.write(query.getBytes(charset));
} catch (Exception e) {
//Here i get Exception that "android: java.net.protocolException: Does not support output"
} finally {
if (output != null)
try {
output.close();
} catch (IOException e) {
}
}
InputStream response = null;
try {
response = connection.getInputStream();
} catch (IOException e) {
//Here i get Exception that "java.io.IOException: BufferedInputStream is closed"
} finally {
//But i am closing it here
connection.disconnect();
}
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(
response, "iso-8859-1"), 8);
sb = new StringBuilder();
sb.append(reader.readLine());
String line = "0";
while ((line = reader.readLine()) != null) {
sb.append("\n" + line);
}
response.close();
result = sb.toString();
} catch (Exception e) {
}
return result;
}
}
But i get such Exceptions as commented in the code.
Actually i am calling MConnections.PostData() twice from my Activity using a AsyncTask. This might cause the Exception: Already Connected but i am using connection.disconnect. But why am i still getting that Exception?
Am i using it the wrong way?
Thank You
For the protocol exception, try adding the following before you call getOutputStream():
connection.setDoOutput(true);
Discovered this answer thanks to Brian Roach's answer here: https://stackoverflow.com/a/14026377/387781
Side note: I was having this issue on my HTC Thunderbolt running Gingerbread, but not on my Nexus 4 running Jelly Bean.