HttpURLConnection timeout solution

From: Niels Campbell ( niels_campbell_at_lycos.co.uk)
Date: 01/23/04
Date: 23 Jan 2004 09:14:16 -0800
After spending nearly 3 days on this problem to come up with a

solution I think it is only right to post the solution.

I found that you can't set the soTimeout on an HttpURLConnection as
the sockets are encapsulated within the HttpURLConnection
implementation.

I found Mike Reiche solution in which he uses a handler to set a
timeout value. This nearly worked. Looking at the code in the rt.jar I
found that the initial timeout was working, but the call
parseHTTP(...) in HttpClient was then attempting a second connection
which had a time out value of 0(infinite).

I modified the code to override the doConnect() in the NetworkClient
and managed to get a timeout occurring. To be exact two timeouts
occur.

It works on
java version "1.4.0_03"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0_03-b04)
Java HotSpot(TM) Client VM (build 1.4.0_03-b04, mixed mode)
and
java version "1.2.2"
Classic VM (build JDK-1.2.2_013, native threads, symcjit)

Anyway here is the code, excuse the formatting.

/* HttpTimeoutURLConnection.java */
import java.net.*;
import java.io.*;
import sun.net.www.http.HttpClient;

// Need to override any function in HttpURLConnection that create a
new HttpClient
// and create a HttpTimeoutClient instead. Those functions are
// connect(), getNewClient(), getProxiedClient()

public class HttpTimeoutURLConnection extends
sun.net.www.protocol.http.HttpURLConnection
{

    public HttpTimeoutURLConnection(URL u, HttpTimeoutHandler handler,
int iSoTimeout)
        throws IOException
    {
        super(u, handler);
        HttpTimeoutClient.setSoTimeout(iSoTimeout);
    }

    public void connect() throws IOException
    {
        if (connected)
        {
            return;
        }

        try
        {
            if ("http".equals(url.getProtocol())) // && !failedOnce <-
PRIVATE
            {
                // for safety's sake, as reported by KLGroup
                synchronized (url)
                {
                    http = HttpTimeoutClient.getNew(url);
                }
            }
            else
            {
                if (handler instanceof HttpTimeoutHandler)
                {
                    http = new HttpTimeoutClient(super.url,
((HttpTimeoutHandler)handler).getProxy(),
((HttpTimeoutHandler)handler).getProxyPort());
                }
                else
                {
                    throw new IOException("HttpTimeoutHandler
expected");
                }
            }

            ps = (PrintStream)http.getOutputStream();
        }
        catch (IOException e)
        {
            throw e;
        }

        connected = true;
    }

    protected HttpClient getNewClient(URL url)
        throws IOException
    {
        HttpTimeoutClient httpTimeoutClient = new HttpTimeoutClient
(url, (String)null, -1);
        return httpTimeoutClient;
    }

    protected HttpClient getProxiedClient(URL url, String s, int i)
        throws IOException
    {
        HttpTimeoutClient httpTimeoutClient = new HttpTimeoutClient
(url, s, i);
        return httpTimeoutClient;
    }

}

/* HttpTimeoutHandler.java */
import java.net.*;
import java.io.IOException;

public class HttpTimeoutHandler extends
sun.net.www.protocol.http.Handler
{
    private int iSoTimeout=0;

    public HttpTimeoutHandler(int iSoTimeout)
    {
        // Divide the time out by two because two connection attempts
are made
        // in HttpClient.parseHTTP()

        if (iSoTimeout%2!=0)
        {
            iSoTimeout++;
        }
        this.iSoTimeout = (iSoTimeout/2);
    }

    protected java.net.URLConnection openConnection(URL u) throws
IOException
    {
        return new HttpTimeoutURLConnection(u, this, iSoTimeout);
    }

    protected String getProxy()
    {
        return proxy;
    }

    protected int getProxyPort()
    {
        return proxyPort;
    }
}

/* HttpTimeoutFactory.java */
import java.net.*;

public class HttpTimeoutFactory implements URLStreamHandlerFactory
{
    private int iSoTimeout=0;

    public HttpTimeoutFactory(int iSoTimeout)
    {
        this.iSoTimeout = iSoTimeout;
    }

    public URLStreamHandler createURLStreamHandler(String str)
    {
        return new HttpTimeoutHandler(iSoTimeout);
    }
}

/* HttpTimeoutClient.java */
import sun.net.www.http.HttpClient;
import java.net.*;
import sun.net.*;
import sun.net.www.*;
import java.io.*;

public class HttpTimeoutClient extends HttpClient
{
    private static int iSoTimeout=0;

    public HttpTimeoutClient(URL url, String proxy, int proxyPort)
throws IOException
    {
        super(url, proxy, proxyPort);
    }

    public HttpTimeoutClient(URL url) throws IOException
    {
        super(url, null, -1);
    }

    public static HttpTimeoutClient getNew(URL url)
        throws IOException
    {
        HttpTimeoutClient httpTimeoutClient = (HttpTimeoutClient)
kac.get(url);

        if (httpTimeoutClient == null)
        {
            httpTimeoutClient = new HttpTimeoutClient (url); // CTOR
called openServer()
        }
        else
        {
            httpTimeoutClient.url = url;
        }

        return httpTimeoutClient;
    }

    public static void setSoTimeout(int iNewSoTimeout)
    {
        iSoTimeout=iNewSoTimeout;
    }

    public static int getSoTimeout()
    {
        return iSoTimeout;
    }

    // Override doConnect in NetworkClient

    protected Socket doConnect(String s, int i)
        throws IOException, UnknownHostException, SocketException
    {
        Socket socket=super.doConnect(s,i);

        // This is the important bit
        socket.setSoTimeout(iSoTimeout);
        return socket;
    }

}

/* Example use */
import java.util.*;
import java.io.*;
import java.net.*;

public class SystemProperty
{
    public static void main(String[] args)
    {
        String sSoapUrl="http://192.168.0.223/mobaqSecurity/SslTunnelServlet";
        System.out.println("Connecting to [" + sSoapUrl + "]");

        URLConnection urlConnection = null;
        URL url=null;

        try
        {
            url = new URL((URL)null, sSoapUrl, new
HttpTimeoutHandler(10000));
            urlConnection = url.openConnection();

            // Optional
            url.setURLStreamHandlerFactory(new
HttpTimeoutFactory(10000));

            System.out.println("Url class
["+urlConnection.getClass().getName()+"]");
        }
        catch (MalformedURLException mue)
        {
            System.out.println(">>MalformedURLException<<");
            mue.printStackTrace();
        }
        catch (IOException ioe)
        {
            System.out.println(">>IOException<<");
            ioe.printStackTrace();
        }

        HttpURLConnection httpConnection =
(HttpURLConnection)urlConnection;
        System.out.println("Connected to [" + sSoapUrl + "]");

        byte[] messageBytes=new byte[10000];
        for (int i=0; i<10000; i++)
        {
            messageBytes[i]=80;
        }

        try
        {
            httpConnection.setRequestProperty("Connection", "Close");
            httpConnection.setRequestProperty("Content-Length",
String.valueOf(messageBytes.length));
            httpConnection.setRequestProperty("Content-Type",
"text/xml; charset=utf-8");
            httpConnection.setRequestMethod("POST");
            httpConnection.setDoOutput(true);
            httpConnection.setDoInput(true);
        }
        catch (ProtocolException pe)
        {
            System.out.println(">>ProtocolException<<");
            pe.printStackTrace();
        }

        OutputStream outputStream=null;

        try
        {
            System.out.println("Getting output stream");
            outputStream =httpConnection.getOutputStream();
            System.out.println("Got output stream");

            outputStream.write(messageBytes);
        }
        catch (IOException ioe)
        {
            System.out.println(">>IOException<<");
            ioe.printStackTrace();
        }

        try
        {
            System.out.println("Getting input stream");
            InputStream is=httpConnection.getInputStream();
            System.out.println("Got input stream");

            byte[] buf = new byte[1000];
            int i;

            while((i = is.read(buf)) > 0)
            {
                System.out.println(""+new String(buf));
            }
            is.close();
        }
        catch (Exception ie)
        {
            ie.printStackTrace();
        }

    }
}

Cheers,
Niels

来源:http://coding.derkeiler.com/Archive/Java/comp.lang.java.programmer/2004-01/3271.html
     http://www.weblogicfans.net/viewthread.php?tid=1101
     http://forums.sun.com/thread.jspa?threadID=568948
备注:在HttpTimeoutClient类中的第二个构造函数中的:super(url,null,-1)改为super(url, (String)null,-1)即可。

你可能感兴趣的:(HttpURLConnection timeout solution)