开发者

HttpsURLConnection stalling out when getInputStream() is called

[Java 1.5; Eclipse Galileo]

HttpsURLConnection seems to stall when the getInputStream() method is called. I've tried using different websites to no avail (currently https://www.google.com). I should point out I'm using httpS.

The code below has been modified based on what I've learned from other StackOverflow answers. However, no solutions I've tried thus far have worked.

I'd be very grateful for a nudge in the right direction :)

public static void request( URL url, String query ) 
{
try{

    HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();

    //connection.setReadTimeout( 5000 ); //<-- uncommenting this line at least allows a timeout error to be thrown

    connection.setDoInput(true); 
    connection.setDoOutput(true);
    connection.setUseCaches(false);  
    System.setProperty("http.keepAlive", "false");


    connection.setRequestMethod( "POST" );


    // setting headers
    connection.setRequestProperty("Content-length",String.valueOf (query.length()));
    connection.setRequestProperty("Content-Type","application/x-www-form-urlencoded"); //WAS application/x-www- form-urlencoded
    connection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt)");

    ////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////
    System.out.println( "THIS line stalls" + connection.getInputStream() );
    ////////////////////////////////////////////////////////////////////////////////////

}catch( Exception e ) {
    System.out.println( e ); 
    e.printStackTrace(); 
}

Typical errors look like:

java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at com.sun.net.ssl.internal.ssl.InputRecord.readFully(InputRecord.java:293)
at com.sun.net.ssl.internal.ssl.InputRecord.read(InputRecord.java:331)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:782)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:739)
at com.sun.net.ssl.internal.ssl.AppInputStream.read(AppInputStream.java:75)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:256)
at java.io.BufferedInputStream.开发者_开发技巧read(BufferedInputStream.java:313)
at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:681)
at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:626)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:983)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:234)
at https_understanding.HTTPSRequest.request(HTTPSRequest.java:60)
at https_understanding.Main.main(Main.java:17)


connection.setDoOutput(true);

This means that you have to open, write to, and close the connection's output stream before you attempt to read from its input stream. See the docs.


I reproduced the problem in Android 2.2: when downloading from a web-server over wireless and a HTTPS URL, the error is a socket "read time out" at URLConnection.getInputStream()

To fix it, use url.openStream() for the InputStream instead of connection.getInputStream()

Bonus: you can get the length of the file you're downloading so you can show a % complete indicator

code sample:

private final int TIMEOUT_CONNECTION = 5000;//5sec
private final int TIMEOUT_SOCKET = 30000;//30sec

file = new File(strFullPath);
URL url = new URL(strURL);
URLConnection ucon = url.openConnection();

//this timeout affects how long it takes for the app to realize there's a connection problem
ucon.setReadTimeout(TIMEOUT_CONNECTION);
ucon.setConnectTimeout(TIMEOUT_SOCKET);


//IMPORTANT UPDATE:
// ucon.getInputStream() often times-out over wireless
// so, replace it with ucon.connect() and url.openStream()
ucon.connect();
iFileLength = ucon.getContentLength();//returns -1 if not set in response header

if (iFileLength != -1)
{
    Log.i(TAG, "Expected Filelength = "+String.valueOf(iFileLength)+" bytes");
}

//Define InputStreams to read from the URLConnection.
// uses 5KB download buffer
InputStream is = url.openStream();//ucon.getInputStream();
BufferedInputStream inStream = new BufferedInputStream(is, 1024 * 5);
outStream = new FileOutputStream(file);
bFileOpen = true;
byte[] buff = new byte[5 * 1024];

//Read bytes (and store them) until there is nothing more to read(-1)
int total=0;
int len;
int percentdone;
int percentdonelast=0;
while ((len = inStream.read(buff)) != -1)
{
    //write to file
    outStream.write(buff,0,len);

    //calculate percent done
    if (iFileLength != -1)
    {
        total+=len;
        percentdone=(int)(total*100/iFileLength);

        //limit the number of messages to no more than one message every 10%
        if ( (percentdone - percentdonelast) > 10)
        {
            percentdonelast = percentdone;
            Log.i(TAG,String.valueOf(percentdone)+"%");
        }
    }
}

//clean up
outStream.flush();//THIS IS VERY IMPORTANT !
outStream.close();
bFileOpen = false;
inStream.close();


Also don't set the content-length header. Java will do that for you.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜