java - Why is android HttpURLConnection not sending back FIN? -


from android app wanted post data server , response back, process send , request. since continuous communication until no more response process, prefer go httpurlconnection http.keepalive = true.

and attempt reuse socket successful, problems facing are:

  1. i trying initiate close client (android app), since if termination starts server server goes time_wait state. , don't want server go state preferred client initiate termination. unfortunately find no suitable way httpurlconnection
  2. after hours of searching gave on doing above attempt , went initiating close server based on keepalivetimeout, when server sends fin, client responds ack, because of connection held on fin_wait_2 in server , close_wait in agent.

packets log snippet

source code:

private httpstatus communicatewithmdmserver(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) {         mdmlogger.error("failed send data server url provided not valid "+ e.getmessage()+"\n");         e.printstacktrace();     } catch (ioexception e) {         mdmlogger.error("failed send status server : ioexception "+ e.getmessage()+"\n"+e.getstacktrace());         e.printstacktrace();         readerrorstreamandprint(connection);     }     connection.disconnect();     return status; }  /**  * api close connection, calling not force connection shutdown  * work based on connection header set.  * @param connection  */ public void closeconnection(){     if(connection != null){         connection.disconnect();     } }   /**  * used initialize httpurlconnection given url  * properties required connection preset here   * connection time out : 20 seconds  * connection type     : keep alive  * content type        : application/json;charset=utf-8  * , certificates evaluated valid.[ todo 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 post data given connection   * call api close @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 read error stream , 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;         }         mdmlogger.error("errorstream says "+responsedata);     } catch (ioexception ioe) {         mdmlogger.debug("exception on reading errorstream");     } }   /**  * api read data given connection , return {@code com.manageengine.mdm.framework.communication.httpstatus}  * call api close @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();     mdmlogger.info("response code: "+responsecode);     inputstream instream = connection.getinputstream();     mdmlogger.info("response header: "+connection.getheaderfields());     string responsedata = "";     if (responsecode == httpurlconnection.http_ok) {         responsedata = readstreamasstring(instream);         status.setstatus(http_status_success);         status.seturldatabuffer(responsedata);         mdmlogger.info("communicatewithmdmserver : response \n"  + status.geturldatabuffer());         mdmlogger.info("successfully send data server , received success response ");     }     else {         status.setstatus(http_status_failure);         mdmlogger.error("data sent failed response , response code : " + responsecode);     }     instream.close();     return status; }  /**  * read inputstream string until eof  * call api 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(); } 

can help?

when use http.keepalive = true connections start recycled, in connection pool, , kept open. if server closes connection it's still listening , client still thinks can send data. after all, server's fin says server not send more data.

since internal logic of connection pool inaccessible have little control. nevertheless, use https, have open window lower layers , can gain access created socket through httpsurlconnection.setsslsocketfactory(sslsocketfactory).

you can create wrapper default factory (sslsocketfactory.getdefault()) allows close socket. simplification bellow:

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

when close underlying socket connection should not eligible recycling , discarded. if closelastsocket , disconnect connection should not go pool , if other way around connection should discarded when create new connection.


Comments

Popular posts from this blog

Magento/PHP - Get phones on all members in a customer group -

php - .htaccess mod_rewrite for dynamic url which has domain names -

Website Login Issue developed in magento -