2

As I am creating a Remote PC application where android is the client and Java is the server. In the below code I am getting screenshots from the Java and displaying it in ImageView of android program. Here Socket connection is running in the background that is Service and I am getting the Socket object to the below Activity using Gson library.

AndroidClient.Java

public class ScreenCast extends Activity {
MyService conn_obj;
public static Socket client;
PrintWriter printwriter;
static ImageView iv;
static Drawable ob;
Socket socket;
Bitmap bitmap;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);                             setContentView(R.layout.activity_screen_cast);
    Gson obj=new Gson();
    String src=getIntent().getStringExtra("clientobj");
    conn_obj= obj.fromJson(src, MyService.class);
    client=MyService.client;
    Log.i("Client Socket",""+client);
    MyTask task=new MyTask();
    task.execute();
}

private class MyTask extends AsyncTask<Void, Void, Bitmap>{
    @SuppressWarnings("deprecation")
    @Override
    protected void onPostExecute(Bitmap result) {
        if(bitmap!=null){
            iv=(ImageView) findViewById(R.id.screenView);
            ob=new BitmapDrawable(getResources(),bitmap);
            iv.setBackgroundDrawable(ob);
        }else{
            Log.d("Bitmap null","Empty");
        }
        MyTask task=new MyTask();
        task.execute();
    }

    @Override
    protected Bitmap doInBackground(Void... arg0){
        try {
            Log.i ("Client Obj",""+client);//check result in log below.
            ObjectInputStream ois=new ObjectInputStream(client.getInputStream());
            byte[] buffer=(byte[]) ois.readObject();
            BitmapFactory.Options options=new BitmapFactory.Options();
            options.inMutable=true;
            bitmap = BitmapFactory.decodeByteArray(buffer, 0, buffer.length,options);
     Ois.close ();
            return bitmap;
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
}

Problem I am facing is: The Socket connection is active till the first screen shot is displayed, after that the Socket connection gets closed and I don’t know where it is getting closed. But strange thing is client is not null at that point. (See log cat before the socket closed error)

LogCat:

2-23 12:39:27.515: I/Client Socket(24599): Socket[address=/192.168.237.1,port=3434,localPort=44496]
02-23 12:39:27.585: D/dalvikvm(24599): GC_FOR_ALLOC freed 319K, 7% free 17667K/18951K, paused 26ms, total 26ms
02-23 12:39:27.620: I/dalvikvm-heap(24599): Grow heap (frag case) to 22.136MB for 4196368-byte allocation
02-23 12:39:27.660: D/dalvikvm(24599): GC_FOR_ALLOC freed 2472K, 17% free 19293K/23111K, paused 41ms, total 41ms
02-23 12:39:27.700: D/dalvikvm(24599): GC_CONCURRENT freed 0K, 17% free 19293K/23111K, paused 12ms+5ms, total 40ms
02-23 12:39:27.815: E/SpannableStringBuilder(24599): SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
02-23 12:39:27.815: E/SpannableStringBuilder(24599): SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
02-23 12:39:27:815: I/Client Socket(24599): Socket[address=/192.168.237.1,port=3434,localPort=44496]
02-23 12:39:27.815: W/System.err(24599): java.net.SocketException: Socket is closed
02-23 12:39:27.835: W/System.err(24599):    at java.net.PlainSocketImpl.checkNotClosed(PlainSocketImpl.java:134)
02-23 12:39:27.835: W/System.err(24599):    at java.net.PlainSocketImpl.getInputStream(PlainSocketImpl.java:216)
02-23 12:39:27.835: W/System.err(24599):    at java.net.Socket.getInputStream(Socket.java:343)
02-23 12:39:27.835: W/System.err(24599):    at com.qubelab.smartcontrol.ScreenCast$MyTask.doInBackground(ScreenCast.java:65)
02-23 12:39:27.835: W/System.err(24599):    at com.qubelab.smartcontrol.ScreenCast$MyTask.doInBackground(ScreenCast.java:1)
02-23 12:39:27.840: W/System.err(24599):    at android.os.AsyncTask$2.call(AsyncTask.java:287)
02-23 12:39:27.840: W/System.err(24599):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
02-23 12:39:27.840: W/System.err(24599):    at java.util.concurrent.FutureTask.run(FutureTask.java:137)
02-23 12:39:27.840: W/System.err(24599):    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
02-23 12:39:27.840: W/System.err(24599):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
02-23 12:39:27.840: W/System.err(24599):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
02-23 12:39:27.840: W/System.err(24599):    at java.lang.Thread.run(Thread.java:856)

Updated Code:

try { 
     if (client.isConnected){ 
         Log.i ("Client Obj",""+client);
         ObjectInputStream ois=new ObjectInputStream(client.getInputStream()); 
         byte[] buffer=(byte[]) ois.readObject(); 
         BitmapFactory.Options options=new BitmapFactory.Options();  
         options.inMutable=true; 
         bitmap = BitmapFactory.decodeByteArray(buffer, 0, buffer.length,options); 
         Ois.close (); 
         return bitmap; 
    } else { 
         Log.d ( " Client", " closed"); 
    } 
} catch(Exception e){ 
     e.printstacktrace();   
}
Suroor Ahmmad
  • 1,110
  • 4
  • 23
  • 33

2 Answers2

1

I tried a modified version of Oracle's echo server and client from Reading from and Writing to a Socket, e.g. client side

Socket echoSocket = new Socket(hostName, portNumber);
ObjectInputStream in = new ObjectInputStream(echoSocket.getInputStream());
/* ... */
in.close();
if (echoSocket.isClosed())
    System.out.println("Socket is closed.");

and as a result, the echo client prints

Socket is closed.

So, when you close the ObjectInputStream for whatever reason, the socket becomes closed as well. And this is the cause for the exception you get

java.net.SocketException: Socket is closed

This means, if you want to read more than one image, you need to reconnect to the server or try to keep the socket open.


To keep the connection open, do not close ois or recreate the ObjectInputStream, e.g.

public class ScreenCast extends Activity {
    private Socket client;

    /* ... */

    private class MyTask extends AsyncTask<Void, Void, Bitmap> {
        private ObjectInputStream ois;

        @Override
        protected void onPreExecute() {
            if (client == null || client.isClosed()) {
                /* reconnect to server somehow */

                ois = null;
            }

            if (ois == null)
                ois = new ObjectInputStream(client.getInputStream());
        }

        @Override
        protected Bitmap doInBackground(Void... arg0) {
            byte[] buffer = (byte[]) ois.readObject();
            /* process image, do *not* close ois */
        }

        @Override
        protected void onPostExecute() {
            /* ... */
        }
    }
}
Olaf Dietsche
  • 72,253
  • 8
  • 102
  • 198
  • I am not willing to reconnect, isit possible to keep socket open – Suroor Ahmmad Feb 25 '15 at 11:36
  • Yes, of course, don't close it. Remove `ois.close()` and keep the `ObjectInputStream`. Right now, you recreate it every time you want to retrieve a new image. – Olaf Dietsche Feb 25 '15 at 12:44
  • I made a small change in my code and here it is: `try { if (client.isConnected){ Log.i ("Client Obj",""+client);//check result in log below. ObjectInputStream ois=new ObjectInputStream(client.getInputStream()); byte[] buffer=(byte[]) ois.readObject(); BitmapFactory.Options options=new BitmapFactory.Options(); options.inMutable=true; bitmap = BitmapFactory.decodeByteArray(buffer, 0, buffer.length,options); Ois.close (); return bitmap; } else { Log.d ( " Client", " closed"); } } catch { }` – Suroor Ahmmad Feb 25 '15 at 12:55
  • as per my knowledge if the client is closed it should execute else part.. but in my program its executing if part – Suroor Ahmmad Feb 25 '15 at 12:56
  • Put the code as an update in the question, it is hard to read as a comment. – Olaf Dietsche Feb 25 '15 at 13:59
  • leave it bro! I think the stream object cannot be created after closing it once – Suroor Ahmmad Feb 25 '15 at 15:26
  • Actually the socket is not getting closed here, but it fails when I try to create stream object which I closed once. thanks for your help. I will try some other way – Suroor Ahmmad Feb 25 '15 at 15:29
  • If you keep the `ObjectInputStream`, you can reuse it. I have done the same in the modified echo server example. First, you create the `ois` and save it somewhere and then you reuse it every time you want to transfer an object (image). – Olaf Dietsche Feb 25 '15 at 17:08
  • Thanks bro! I'll chexk it – Suroor Ahmmad Feb 26 '15 at 12:42
  • So, executing in onPreExecute will cause NetworkOnMainThreadException :/ – Suroor Ahmmad Feb 26 '15 at 16:31
  • Ok, it seems `onPreExecute` is run on the main thread, see http://stackoverflow.com/q/6343166/1741542. So you need to move the code from `onPreExecute` to `doInBackground`. – Olaf Dietsche Feb 26 '15 at 17:55
  • tried this method and its also not working.. it give End of file exception. – Suroor Ahmmad Feb 26 '15 at 18:09
  • and as your suggestion, ois will never go null; b'cos it will not enter `if (client.isClosed)` block – Suroor Ahmmad Feb 26 '15 at 18:25
  • If there's an `EOFException`, then the stream was closed either in the client or in the server code. `if (client.isClosed())` is only a precaution. – Olaf Dietsche Feb 26 '15 at 19:34
  • I think its time to drop this here :/ – Suroor Ahmmad Feb 27 '15 at 09:42
0

insted of using

import java.io*;

use

import java.nio*;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;

these helps to bind your connection persistently. just search for example on SocketChannel in java

Sushant Patekar
  • 421
  • 1
  • 5
  • 17