【问题标题】:TCP Socket connection gets closed even though it is running in Android Service即使它在 Android 服务中运行,TCP Socket 连接也会关闭
【发布时间】:2015-02-23 07:31:33
【问题描述】:

我正在创建一个远程 PC 应用程序,其中 android 是客户端,Java 是服务器。在下面的代码中,我从 Java 获取屏幕截图并将其显示在 android 程序的ImageView 中。这里Socket 连接在Service 的后台运行,我正在使用Gson 库将Socket 对象传递给下面的活动。

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;
    }
}

我面临的问题是: Socket 连接一直处于活动状态,直到显示第一个屏幕截图,之后 Socket 连接关闭,我不知道它在哪里关闭。 但奇怪的是客户端在这一点上不是空的。 (在socket关闭错误之前查看日志cat)

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)

更新代码:

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();   
}

【问题讨论】:

  • 检查您的 logcat - at com.qubelab.smartcontrol.ScreenCast$MyTask.doInBackground(ScreenCast.java:65) 意味着您需要查看 ScreenCast.java 文件中的第 65 行。
  • 这是-65行` ObjectInputStream ois=new ObjectInputStream(client.getInputStream());`
  • 在该位置程序无法创建 ObjectInputStream 对象,因为 Socket 已关闭。我想知道为什么Socket 连接即使在后台运行也会关闭?
  • 服务器关闭连接?
  • Ois.close ();。你的意思是ois.close ();。认为关闭和重新打开流会带来麻烦。

标签: android android-asynctask asyncsocket objectinputstream


【解决方案1】:

我尝试了来自Reading from and Writing to a Socket 的 Oracle 回显服务器和客户端的修改版本,例如客户端

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

结果,echo 客户端打印

套接字已关闭。

因此,当您出于某种原因关闭ObjectInputStream 时,套接字也会关闭。这就是你得到异常的原因

java.net.SocketException: 套接字已关闭

这意味着,如果要读取多个图像,则需要重新连接到服务器或尝试保持套接字打开。


要保持连接打开,请不要关闭ois 或重新创建ObjectInputStream,例如

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() {
            /* ... */
        }
    }
}

【讨论】:

  • 我不愿意重新连接,是否可以保持套接字打开
  • 是的,当然,不要关闭它。删除 ois.close() 并保留 ObjectInputStream。现在,您每次要检索新图像时都重新创建它。
  • 我对我的代码做了一个小改动,这里是: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 { }
  • 据我所知,如果客户端关闭,它应该执行 else 部分.. 但在我的程序中它正在执行 if 部分
  • 将代码作为更新放在问题中,作为评论很难阅读。
【解决方案2】:

习惯使用

import java.io*;

使用

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

这些有助于持久绑定您的连接。 只需在 java 中的 SocketChannel 上搜索示例

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-05
    • 2021-12-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多