Java 为什么android HttpURLConnection没有发送回FIN?

Java 为什么android HttpURLConnection没有发送回FIN?,java,android,tcp,httpurlconnection,keep-alive,Java,Android,Tcp,Httpurlconnection,Keep Alive,从我的安卓应用程序中,我想将数据发布到服务器并获得响应,处理它,然后发送回并获得另一个请求。由于它是持续的通信,直到对进程没有更多响应为止,我更喜欢使用HttpURLConnectionhttp.keepAlive=true 我尝试重用socket是成功的,但我面临的问题是: 我正在尝试从客户端启动Close(Android应用程序),因为如果 终止从服务器开始,然后服务器转到 等待时间状态。我不希望我的服务器进入那种状态,所以我更希望我的客户端启动终止。但不幸的是 我找不到合适的方法来使用Ht

从我的安卓应用程序中,我想将数据发布到服务器并获得响应,处理它,然后发送回并获得另一个请求。由于它是持续的通信,直到对进程没有更多响应为止,我更喜欢使用
HttpURLConnection
http.keepAlive=true

我尝试重用socket是成功的,但我面临的问题是:

  • 我正在尝试从客户端启动Close(Android应用程序),因为如果 终止从服务器开始,然后服务器转到
    等待时间
    状态。我不希望我的服务器进入那种状态,所以我更希望我的客户端启动终止。但不幸的是 我找不到合适的方法来使用
    HttpURLConnection
  • 经过数小时的搜索,我放弃了上述尝试,并 已根据从服务器启动关闭
    keepalivetimeout
    ,但当服务器发送
    FIN
    时,客户端只响应
    ,因为该连接被中断
    FIN\u WAIT\u 2
    在服务器中,并
    关闭\u WAIT
    在代理中
  • 源代码:

    private HttpStatus communicateWithServer(String httpUrl, String dataToSend, boolean keepAlive) {
        HttpStatus status = new HttpStatus(HTTP_STATUS_FAILURE);
        
        try {
            
            initializeConnection(httpUrl,keepAlive);
            postDataToConnection(connection, dataToSend);
            status = readDataFromConnection(connection);
            
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
            readErrorStreamAndPrint(connection);
        }
        connection.disconnect();
        return status;
    }
    
    /**
     * API to close connection, calling this will not force the connection to shutdown
     * this will work based on the Connection header set.
     * @param connection
     */
    public void closeConnection(){
        if(connection != null){
            connection.disconnect();
        }
    }
    
    
    /**
     * Used to initialize the HttpURLConnection for the given url
     * All properties required for connection are preset here 
     * Connection Time Out : 20 Seconds
     * Connection Type     : keep alive
     * Content Type        : application/json;charset=UTF-8
     * And also All certificates will be evaluated as Valid.[ TODO will be removed soon]
     * @param httpUrl
     * @return
     * @throws MalformedURLException
     * @throws IOException
     */
    private void initializeConnection(String httpUrl, boolean keepAlive) throws MalformedURLException, IOException{
        
        URL url = new URL(httpUrl);
        connection = (HttpsURLConnection) url.openConnection();
        
        connection.setConnectTimeout(20000);
        connection.setReadTimeout(20000);
        connection.setDoInput(true);
        connection.setDoOutput(true);
        connection.setRequestMethod("POST");                                                                        //NO I18N
        connection.setRequestProperty("Content-Type", "application/json;charset=UTF-8");                            //NO I18N
        connection.setRequestProperty("Connection", "Keep-Alive");      //NO I18N
    }
    
    
    /**
     * API to post data to given connection 
     * call to this API will close the @OutputStream
     * @param connection
     * @param data
     * @throws IOException
     */
    private void postDataToConnection(URLConnection connection , String data) throws IOException{
        
        OutputStream outStream = connection.getOutputStream();
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outStream));
        writer.write(data);
        writer.flush();
        writer.close();
        outStream.close();
    }
    
    /**
     * API to read error stream and log
     * @param connection
     */
    private void readErrorStreamAndPrint(URLConnection connection){
        try{
            InputStream inStream = ((HttpURLConnection) connection).getErrorStream();
            String responseData = "";
            String line;
            BufferedReader br=new BufferedReader(new InputStreamReader(inStream));
            while ((line=br.readLine()) != null) {
                responseData+=line;
            }
            
        } catch (IOException ioe) {
            
        }
    }
    
    
    /**
     * API to read data from given connection and return 
     * call to this API will close the @InputStream
     * @param connection
     * @return
     * @throws IOException
     */
    private HttpStatus readDataFromConnection(URLConnection connection) throws IOException{
        
        HttpStatus status = new HttpStatus(HTTP_STATUS_FAILURE);
        int responseCode=((HttpURLConnection) connection).getResponseCode();
        InputStream inStream = connection.getInputStream();
        String responseData = "";
        if (responseCode == HttpURLConnection.HTTP_OK) {
            responseData = readStreamAsString(inStream);
            status.setStatus(HTTP_STATUS_SUCCESS);
            status.setUrlDataBuffer(responseData);
        }
        else {
            status.setStatus(HTTP_STATUS_FAILURE);
        }
        inStream.close();
        return status;
    }
    
    /**
     * Read the InputStream to String until EOF
     * Call to this API will not close @InputStream
     * @param inStream
     * @return
     * @throws IOException
     */
    private String readStreamAsString(InputStream inStream) throws IOException{
        StringBuilder responseData = new StringBuilder();
        String line;
        BufferedReader br=new BufferedReader(new InputStreamReader(inStream));
        while ((line=br.readLine()) != null) {
            responseData.append(line);
        }
        return responseData.toString();
    }
    

    有人能帮忙吗?

    我发现了一些有趣的想法

    以下是有关FIN的一些信息:

    在这里,重要的是要理解
    connection.disconnect()
    不保证触发FIN。从
    HttpURLConnection
    的文档:

    读取响应正文后,应通过调用
    disconnect()
    关闭
    HttpURLConnection
    。 断开连接将释放连接所持有的资源,以便可以关闭或重用这些资源

    这里的重点放在梅身上:正如你从上一篇文章中看到的那样 屏幕截图,是服务器决定终止连接 在某个时刻,而不是我们要求断开连接,因为第一个鳍是
    由目标而不是源发送。

    当您使用
    http.keepAlive=true
    时,连接开始在连接池中循环,并保持打开状态。即使服务器关闭了连接,它仍在侦听,客户端仍认为它可以发送数据。毕竟,服务器的
    FIN
    只是说服务器不会发送更多数据

    由于连接池的内部逻辑不可访问,因此您几乎无法控制。尽管如此,当您使用https时,您有一个打开的窗口可以访问较低层,并且可以通过
    HttpsURLConnection.setsssocketfactory(SSLSocketFactory)
    访问创建的
    套接字

    您可以为默认工厂(
    SSLSocketFactory.getDefault()
    )创建一个包装器,该包装器允许关闭
    套接字。类似于下面的简化:

    public class MySSLSocketFactory extends SSLSocketFactory {
    
        private SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
        private Socket last;
    
        public void closeLastSocket() {
            if (last != null) {
                last.close();
            }
        }
    
        public Socket createSocket() throws IOException {
            return this.last = factory.createSocket();
        }
    
        ...
    
    }
    

    当您关闭基础套接字时,连接不应符合回收条件,将被丢弃。因此,如果您执行
    closeLastSocket
    disconnect
    操作,则连接甚至不应进入池中,如果您执行其他操作,则只有在创建新连接时,连接才会被丢弃。

    使用
    HttpURLConnection执行此操作的合适方法是
    HttpURLConnection.disconnect().`但这只是一个提示。@EJP我在事务结束时使用了disconnect(),但我没有发现任何区别,请您详细说明一下。