提问者:小点点

Android httpConnection上的socket-io内存泄漏


我在android上使用socket-io。('com.github.nkzawa:socket.io-client:0.3.0')

在Nexus10设备(Android 4.2.1)上测试我的应用程序时,我发现调用msocket.connect()后,libcore.net.http.HttpConnectionPool每隔12.7秒左右就会创建一个libcore.net.http.HttpConnection对象。这会导致“太多打开文件错误”,最终导致应用程序冻结或崩溃。

  • 在(Android 4.4.2)Samsung GS5设备上不发生
  • 如果连接到非SSL服务器(http vs https),则不会发生这种情况
  • 我正在连接到自签名证书服务器-不确定它是否与泄漏有关。
  • 调用套接字断开连接不会释放HttpConnection对象

在调查漏洞时,我创建了一个空的android项目来重现漏洞。下面我只附上了添加在一个空的“Hello World”项目顶部的代码。

>

  • 注意,在我的原始应用程序上-与服务器的连接是成功的。onError回调会被放置,但不会被调用。在服务器端,只建立了一个连接。发送和接收消息是成功的。只有当HttpConnection对象计数达到300左右时,才会出现“打开文件太多”错误并导致各种问题。

    事实上,它只发生在一些android版本上,只发生在SSL连接上,连接导致泄漏,但断开连接并不能释放它,这真的让我感到困惑。

    添加到build.gradle依赖项

    compile 'com.github.nkzawa:socket.io-client:0.3.0'
    

    添加到Android清单

    <uses-permission android:name="android.permission.INTERNET" />
    

    主activity.。。。

    import com.github.nkzawa.socketio.client.IO;
    import com.github.nkzawa.socketio.client.Socket;
    
    import java.net.URISyntaxException;
    import java.security.KeyManagementException;
    import java.security.NoSuchAlgorithmException;
    import java.security.cert.CertificateException;
    import java.security.cert.X509Certificate;
    
    import javax.net.ssl.HostnameVerifier;
    import javax.net.ssl.HttpsURLConnection;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLSession;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.X509TrustManager;
    
    
    public class MainActivity extends AppCompatActivity {
    
    
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        .....
    
        mSocket.connect();
    }
    
    private TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return new java.security.cert.X509Certificate[] {};
            }
    
        public void checkClientTrusted(X509Certificate[] chain,String authType) throws CertificateException {
        }
    
        public void checkServerTrusted(X509Certificate[] chain,
                                       String authType) throws CertificateException {
        }
    } };
    private Socket mSocket;
    {
    
            try
            {
                SSLContext sc = SSLContext.getInstance("TLS");
                sc.init(null, trustAllCerts, null);
                IO.setDefaultSSLContext(sc);
                HttpsURLConnection.setDefaultHostnameVerifier(new RelaxedHostNameVerifier());
    
                mSocket = IO.socket("https://10.0.0.1");
                mSocket.connect() ;
    
            }
            catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (KeyManagementException e) {
                e.printStackTrace();
            }
            catch (URISyntaxException e) {
                e.printStackTrace();
            }
    
    }
    
    public static class RelaxedHostNameVerifier implements HostnameVerifier {
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    }
    

  • 共1个答案

    匿名用户

    好的。明白了。

    • 每12.7秒的连接泄漏是ping。更改我的服务器上的ping间隔会有一些帮助。但事实证明,httpConnection在发送到服务器的每条消息上都被泄露了。所以基本上它不是一个解决方案。

    经过一点点挖掘,我在网上找到了这个。http://android-developers.blogspot.co.il/2011/09/androids-http-clients.html

    总结一下。

    “在Froyo之前,HttpURLConnection有一些令人沮丧的bug.特别是,对可读的InputStream调用close()可能会毒害连接池。请通过禁用连接池来解决此问题:”

    private void disableConnectionReuseIfNecessary() {
        // HTTP connection reuse which was buggy pre-froyo
        if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) {
            System.setProperty("http.keepAlive", "false");
        }
    }
    

    就像我说的那样,我受的是软糖豆漏,而不是弗罗约。我去掉了条件。

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        System.setProperty("http.keepAlive", "false") ;
        ...
    }