Android: How to set timeout for OutputStream? - android

I used Socket to communicate with Client. I've problem for setting the timeout for OutputStream. The Socket itself already set the timeout. When I didn't set the timeout for OutputStream, when the internet connection is shut down at OutputStream out = socket.getOutputStream(), the IOException will thrown after 15 minutes. It will affect the user experience itself.
Socket.java
// Create an SSLContext that uses our TrustManager
final SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
SSLSocket socket = null;
try{
SSLSocketFactory sslsocketfactory = context.getSocketFactory();
socket = (SSLSocket) sslsocketfactory.createSocket();
socket.connect(new InetSocketAddress(<dstAddress>, <dstPort>), <timeout>);
// Here is the point when the internet connection is loss
OutputStream out = socket.getOutputStream();
out.write(BytesUtil.hexStringToBytes(<requestParams>));
out.flush();
} catch(SocketTimeoutException se) {
se.printStackTrace();
} catch (IOException e) {
// Will thrown after 15 minutes
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
// close socket
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}

See Socket and ServerSocket. Both classes have a setSoTimeout method to specify the maximum time to wait when waiting for connections or waiting to receive data. When that time has elapsed, the socket throws a SocketTimeoutException that you can handle with your error message or however you want.
You have to call setSoTimeout() before performing the actions you want to have a timeout.
Prior to
while ((numberReceived = socketInputStream.read(buffer)) != -1) {
//You'll need to call
socket.setSoTimeout(2000);
And then add a catch(SocketTimeoutException) section to the try/catch block you already have.

Related

Check if RESTful server is available on Android

I'm developping an Android REST-API oriented application.
I need to create a method to check whether the server is available or not.
The problem is if you use the URL.openStream() method, there's no way to determine whether a request was successful or not.
Is there a way to do it without the need to operate of performing a full HttpURLConnection and read the return code?
You can use TCP Sockets
SocketAddress socketAddress = new InetSocketAddress(address, port);
try {
int timeout = 2000;
socket.connect(socketAddress, timeout);
}
catch (IOException e) {
return false;
}
finally {
if (socket.isConnected()) {
try {
socket.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}

Android: Quick web requests

For my application I need to have the latest data from an webpage that is hosted on a server on my local network.
So I request the latest page with a HTTP GET and when the data is received, I send another request.
With my current implementation I reach around the 100 - 120 ms per request. Is there a possibility to make this quicker because it's the same url that is requested.
For example keep the connection open to the page and grep the latest data without setting up a new connection?
This page is around the 900-1100 bytes.
HTTP get code:
public static String makeHttpGetRequest(String stringUrl) {
try {
URL url = new URL(stringUrl);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setReadTimeout(300);
con.setConnectTimeout(300);
con.setDoOutput(false);
con.setDoInput(true);
con.setChunkedStreamingMode(0);
con.setRequestMethod("GET");
return readStream(con.getInputStream());
} catch (IOException e) {
Log.e(TAG, "IOException when setting up connection: " + e.getMessage());
}
return null;
}
Reading inputstream
private static String readStream(InputStream in) {
BufferedReader reader = null;
StringBuilder total = new StringBuilder();
try {
String line = "";
reader = new BufferedReader(new InputStreamReader(in));
while ((line = reader.readLine()) != null) {
total.append(line);
}
} catch (IOException e) {
Log.e(TAG, "IOException when reading InputStream: " + e.getMessage());
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return total.toString();
}
As I know there isn't an implementation like you are asking for. I've been dealing a lot with http requests and the best thing you can do is your code. There is another thing which need some attention...your connection maybe slow and depending on that connection time can be more or in some cases which I've been dealing a lot the connection's timeout isn't enough big, but that's server problem.
In my opinion you should use what you have now.

Data transfer between two Wifi devices

I have searched in Google. In Android 2.2 and sdk 8 how can I use SSID in a List in Android ?
By using SSID should get specific wifi enabled device properties by programmatically. With that help, should transfer the data between two Wifi enabled devices in Android.
To send data in a meaningful manner between two Android devices you would use a TCP connection. To do that you need the ip address and the port on which the other device is listening.
Examples are taken from here.
For the server side (listening side) you need a server socket:
try {
Boolean end = false;
ServerSocket ss = new ServerSocket(12345);
while(!end){
//Server is waiting for client here, if needed
Socket s = ss.accept();
BufferedReader input = new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintWriter output = new PrintWriter(s.getOutputStream(),true); //Autoflush
String st = input.readLine();
Log.d("Tcp Example", "From client: "+st);
output.println("Good bye and thanks for all the fish :)");
s.close();
if ( STOPPING conditions){ end = true; }
}
ss.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
For the client side you need a socket that connects to the server socket. Please replace "localhost" with the remote Android devices ip-address or hostname:
try {
Socket s = new Socket("localhost",12345);
//outgoing stream redirect to socket
OutputStream out = s.getOutputStream();
PrintWriter output = new PrintWriter(out);
output.println("Hello Android!");
BufferedReader input = new BufferedReader(new InputStreamReader(s.getInputStream()));
//read line(s)
String st = input.readLine();
//. . .
//Close connection
s.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
For data Transfer between 2 devices over the wifi can be done by using "TCP" protocol. Connection between Client and Server requires 3 things
Using NSD Manager, Client device should get server/host IP Address.
Send data to server using Socket.
Client should send its IP Address to server/host for bi-directional communication.
For faster transmission of data over wifi can be done by using "WifiDirect"
which is a "p2p" connection. so that this will transfer the data from one to other device without an Intermediate(Socket). For example, see this link in google developers wifip2p and P2P Connection with Wi-Fi.
Catch a sample in Github WifiDirectFileTransfer

Do I need to call HttpURLConnection.disconnect after finish using it

The following code basically works as expected. However, to be paranoid, I was wondering, to avoid resource leakage,
Do I need to call HttpURLConnection.disconnect, after finish its usage?
Do I need to call InputStream.close?
Do I need to call InputStreamReader.close?
Do I need to have the following 2 line of code : httpUrlConnection.setDoInput(true) and httpUrlConnection.setDoOutput(false), just after the construction of httpUrlConnection?
The reason I ask so, is most of the examples I saw do not do such cleanup. http://www.exampledepot.com/egs/java.net/post.html and http://www.vogella.com/articles/AndroidNetworking/article.html. I just want to make sure those examples are correct as well.
public static String getResponseBodyAsString(String request) {
BufferedReader bufferedReader = null;
try {
URL url = new URL(request);
HttpURLConnection httpUrlConnection = (HttpURLConnection)url.openConnection();
InputStream inputStream = httpUrlConnection.getInputStream();
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
int charRead = 0;
char[] buffer = new char[1024];
StringBuffer stringBuffer = new StringBuffer();
while ((charRead = bufferedReader.read(buffer)) > 0) {
stringBuffer.append(buffer, 0, charRead);
}
return stringBuffer.toString();
} catch (MalformedURLException e) {
Log.e(TAG, "", e);
} catch (IOException e) {
Log.e(TAG, "", e);
} finally {
close(bufferedReader);
}
return null;
}
private static void close(Reader reader) {
if (reader != null) {
try {
reader.close();
} catch (IOException exp) {
Log.e(TAG, "", exp);
}
}
}
Yes you need to close the inputstream first and close httpconnection next. As per javadoc.
Each HttpURLConnection instance is used to make a single request but the underlying network connection to the HTTP server may be transparently shared by other instances. Calling the close() methods on the InputStream or OutputStream of an HttpURLConnection after a request may free network resources associated with this instance but has no effect on any shared persistent connection. Calling the disconnect() method may close the underlying socket if a persistent connection is otherwise idle at that time.
Next two questions answer depends on purpose of your connection. Read this link for more details.
I believe the requirement for calling setDoInput() or setDoOutput() is to make sure they are called before anything is written to or read from a stream on the connection. Beyond that, I'm not sure it matters when those methods are called.

Android and sockets - CorruptedStreamException

I'm writing a small app that's supposed to mirror moves made on another phone during a game of tetris. It works perfectly for a little while, untill i get a CorruptedStreamException on the server side while writing an object.
Here's the code for the server:
public void run() {
ServerSocket ss = null;
Socket s = null;
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
try{
ss = new ServerSocket(PORT);
s = ss.accept();
Log.i(TAG,"accepted");
oos.flush();
ois = new ObjectInputStream(s.getInputStream());
while(run){
busy=true;
oos.writeObject(positions);
busy = false;
this.sleep(100);
oos.reset();
}
} catch (Exception e) {
e.printStackTrace();
}finally{//close sockets!!
try{
ois.close();
oos.close();
s.close();
ss.close();
}catch(Exception e){}
}
}
I'll toss out the client side code too:
public void run() {
Canvas c = null;
Socket s = null;
ObjectInputStream ois = null;
ObjectOutputStream oos = null;
try {
Log.i(TAG, "it entered try");
s = new Socket(IP, PORT);
oos = new ObjectOutputStream(s.getOutputStream());
oos.flush();
ois = new ObjectInputStream(s.getInputStream());
Log.i("try","has connected");
while(run){
blockList=(ArrayList<Posision>)ois.readObject();
if(blockList!=null){
try{
c=mSurfaceHolder.lockCanvas(null);
synchronized(mSurfaceHolder){
mTetrisView.drawTetris(c, blockList);
}
}finally{
if(c!=null){
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}catch (EOFException ez){
Log.i("catch", "End of file");
} catch (Exception e) {
Log.i("catch",e.getMessage());
e.printStackTrace();
}finally{//close socket!!
try{
ois.close();
oos.close();
s.close();
}catch(IOException e){}
}
}
And a stack trace might come in handy too, when thinking of it:
java.io.StreamCorruptedException
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1712)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1665)
at com.prosjekt.tetris2.ServerThread.run(ServerThread.java:42)
Now why am I getting this error? As far as I know, writeObject() shouldn't be able to throw it.
I'm not really sure how I figured this out, but turns out that the client thread didn't print the errors it got (this however, doesn't explain why the server side threw the corruptedStreamException). The fault lay with the client getting a OptionalDataException with the length field set to 0 (indicates end of stream). I knew for a fact that the writeObject were called often enough that this shouldn't be a problem, so I decided to rewrite part of the code.
The final fix is really too simple, and this is how my while loop at server side looked like after rewriting:
while(run){
oos.writeObject(new ArrayList<Posisions>(positions));
oos.flush();
}
There's viritually no changes to the client side, so I guess the rate of resets() somehow stomped the stream.

Categories

Resources