如何通过HTTP代理连接Socket服务器

时间:2011-08-29 03:45:59

标签: java sockets httpclient

我有一段代码连接到Socket服务器,它工作正常。

Socket socket = new Socket();
socket.connect(new InetSocketAddress(address, port));

现在我想通过HTTP代理连接,我该怎么办?

我试过这个并且失败了

SocketAddress proxyAddr = new InetSocketAddress(proxyHost, proxyPort);
Proxy proxy = new Proxy(Proxy.Type.SOCKS, addr);
Socket socket = new Socket(proxy);
socket.connect(new InetSocketAddress(address, port));

this post建议我应该使用 Jakarta Commons HttpClient ,但如何使用它通过HTTP代理连接Socket服务器?

更新: 我使用SOCKS代理,如果我使用HTTP代理它不起作用:

SocketAddress proxyAddr = new InetSocketAddress(proxyHost, proxyPort);
Proxy proxy = new Proxy(Proxy.Type.HTTP, addr);
Socket socket = new Socket(proxy);
socket.connect(new InetSocketAddress(address, port));

它将抛出IllegalArgumentException

java.lang.IllegalArgumentException: Proxy is null or invalid type
    at java.net.Socket.<init>(Socket.java:88)

9 个答案:

答案 0 :(得分:4)

我创建了一个小型Socket Factory类来通过socket处理HTTP CONNECT。然后,如果代理支持CONNECT到目的地,则可以按普通方式使用套接字。

public final class SocketFactory {

    public static Socket GetSocket(String host, String port) throws IOException {

        /*************************
         * Get the jvm arguments
         *************************/

        int proxyPort = Integer.parseInt(System.getProperty("http.proxyPort"));
        String proxyHost = System.getProperty("http.proxyHost");

        // Socket object connecting to proxy
        Socket sock = new Socket(proxyHost, proxyPort);

        /***********************************
         * HTTP CONNECT protocol RFC 2616
         ***********************************/
        String proxyConnect = "CONNECT " + host + ":" + port;

        // Add Proxy Authorization if proxyUser and proxyPass is set
        try {
            String proxyUserPass = String.format("%s:%s",
                    System.getProperty("http.proxyUser"),
                    System.getProperty("http.proxyPass"));

            proxyConnect.concat(" HTTP/1.0\nProxy-Authorization:Basic "
                    + Base64.encode(proxyUserPass.getBytes()));
        } catch (Exception e) {
        } finally {
            proxyConnect.concat("\n\n");
        }

        sock.getOutputStream().write(proxyConnect.getBytes());
        /***********************************/

        /***************************
         * validate HTTP response.
         ***************************/
        byte[] tmpBuffer = new byte[512];
        InputStream socketInput = sock.getInputStream();

        int len = socketInput.read(tmpBuffer, 0, tmpBuffer.length);

        if (len == 0) {
            throw new SocketException("Invalid response from proxy");
        }

        String proxyResponse = new String(tmpBuffer, 0, len, "UTF-8");

        // Expecting HTTP/1.x 200 OK
        if (proxyResponse.indexOf("200") != -1) {

            // Flush any outstanding message in buffer
            if (socketInput.available() > 0)
                socketInput.skip(socketInput.available());

            // Proxy Connect Successful, return the socket for IO
            return sock;
        } else {
            throw new SocketFactoryException("Fail to create Socket",
                    proxyResponse);
        }
    }

    /**
     * Simplest Base64 Encoder adopted from GeorgeK
     * 
     * @see http://stackoverflow.com/questions/469695/decode-base64-data-in-java/4265472#4265472
     */
    private static class Base64 {
        /***********************
         * Base64 character set
         ***********************/
        private final static char[] ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
                .toCharArray();

        /**
         * Translates the specified byte array into Base64 string.
         * 
         * @param buf
         *            the byte array (not null)
         * @return the translated Base64 string (not null)
         */
        public static String encode(byte[] buf) {
            int size = buf.length;
            char[] ar = new char[((size + 2) / 3) * 4];
            int a = 0;
            int i = 0;
            while (i < size) {
                byte b0 = buf[i++];
                byte b1 = (i < size) ? buf[i++] : 0;
                byte b2 = (i < size) ? buf[i++] : 0;

                int mask = 0x3F;
                ar[a++] = ALPHABET[(b0 >> 2) & mask];
                ar[a++] = ALPHABET[((b0 << 4) | ((b1 & 0xFF) >> 4)) & mask];
                ar[a++] = ALPHABET[((b1 << 2) | ((b2 & 0xFF) >> 6)) & mask];
                ar[a++] = ALPHABET[b2 & mask];
            }
            switch (size % 3) {
            case 1:
                ar[--a] = '=';
            case 2:
                ar[--a] = '=';
            }
            return new String(ar);
        }
    }
}

https://code.google.com/p/java-socket-over-http-proxy-connect/

答案 1 :(得分:2)

您可以尝试JHttpTunnel,但您需要在隧道两侧运行软件才能实现此目的。

答案 2 :(得分:2)

这是我之前发布的链接:

SocketAddress addr = new InetSocketAddress("webcache.mydomain.com", 8080);
Proxy proxy = new Proxy(Proxy.Type.HTTP, addr);

请记住,这个新的代理对象代表了一个代理定义,仅此而已。我们如何使用这样的对象?新的openConnection()方法已添加到URL类中,并将Proxy作为参数,它的工作方式与openConnection()的方式相同,不带参数,但强制通过指定的代理建立连接,忽略所有其他设置,包括上面提到的系统属性。

完成上一个示例后,我们现在可以添加:

URL url = new URL("http://java.sun.com/");
URLConnection conn = url.openConnection(proxy);

这是我之前发布的链接。我在iPad上,所以无法正确格式化。

你能这样做吗?我看到你正在直接进行套接字,但你正在做http,所以也许这样做?

答案 3 :(得分:0)

看起来您正在请求SOCKS代理,该代理与HTTP代理不同。也许尝试Proxy.Type.HTTP。

问题:您的客户端是基于HTTP吗?除非你的客户说HTTP,否则我不确定这是否有效。

答案 4 :(得分:0)

根据维基百科HTTP tunneling,关于HTTP代理的重要之处在于它代理了HTTP协议。

因此,如果您有服务器和客户端并希望它们通过HTTP代理进行通信,则必须修改服务器和客户端以通信HTTP协议。

或者,您需要其他可以实现VPN over HTTP的软件,例如OpenVPN。

编辑:一个例外是某些HTTP代理服务器支持并启用了一个名为HTTP CONNECT的方法,该方法通过HTTP进行基本设置过程后,允许创建和路由常规TCP套接字。这允许连接到应用程序,而无需完全转换为HTTP隧道的艰苦工作。一个很好的例子就是MSN Messenger。但是,正如维基百科的文章所述,这个功能经常被禁用,或者出于安全原因甚至不支持。

答案 5 :(得分:0)

我是否正确地说你想要的是使用http代理(例如鱿鱼)来建立到远程服务器的CONNECT方法(来自http rfc 2616)?基本上,连接是这样的:

     -open a socket to the proxy (host, port)
     -send text to the proxy with basic header 
     ....CONNECT remote.internethost.com:1494 HTTP/1.0
     ....User-Agent: Java Proxy Socket version 1.0a
     ....Host: remote.internethost.com
     ....Proxy-Authorization: Basic YourBase64usernamePasswordIfRequired
     -then, the proxy will return a http status code (multiline text string) and the actual socket (if successfull)
     -this is this socket that needs to be returned to the connection object

这可以通过个人课程完成,但美妙的是重用代理类。这样,所有与http代理的握手,特别是响应代码都将被处理。

答案 6 :(得分:0)

嗯,您可以通过在代理的网址后面设置请求的网址,或者使用Java网址来管理代理:

URL u = new URL("http", ProxyHost, ProxyPort, destinationAddress);

通过使用它,您可以构建一个类似http://ProxyHost:ProxyPorthttp://destinationAddress的URL,这样您就不必在Java中设置可能引发上述异常的Proxy类实例:

java.lang.IllegalArgumentException: Proxy is null or invalid type
    at java.net.Socket.<init>(Socket.java:88)

如果您需要管理身份验证设置,您始终可以将身份验证器设置为默认设置。

final String authUser = myAuthUser;
        final String authPassword = myAuthPassword;
        Authenticator.setDefault(
           new Authenticator() {
              public PasswordAuthentication getPasswordAuthentication() {
                 return new PasswordAuthentication(
                       authUser, authPassword.toCharArray());
              }
           }
        );

即使这是设置代理的一种非常“基本”的方式,如果这是您必须设置的代理类型,它很可能适用于HTTP类型代理。

答案 7 :(得分:0)

我看到一个很老的帖子,不知道有没有人在找这个。对我来说,打击片段工作得很好。

Socket socketProxy = null;
    if(System.getProperty("http.proxyHost") != null) {
        if(System.getProperty("http.proxyUser") != null) {
            
            String proxyUser = System.getProperty("http.proxyUser");
            String proxyPassword = System.getProperty("http.proxyPassword");
            
            //For Proxy Authentication
            Authenticator.setDefault( new Authenticator() {
            
             @Override public PasswordAuthentication getPasswordAuthentication() { return
             new PasswordAuthentication(proxyUser, proxyPassword.toCharArray()); } } ); 
             
             System.setProperty("jdk.http.auth.tunneling.disabledSchemes", ""); // By default basic auth is disabled, by this basic auth is enabled
        }
    Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(System.getProperty("http.proxyHost"), Integer.parseInt(System.getProperty("http.proxyPort"))));
    socketProxy = new Socket(proxy);
    InetSocketAddress address = InetSocketAddress.createUnresolved(host, port); // create a socket without resolving the target host to IP
    socketProxy.connect(address); 
    }

我从原始帖子中注意到的一件事是没有使用 proxyAddr。不知道是这篇文章中的错别字还是错误。

SocketAddress **proxyAddr** = new InetSocketAddress(proxyHost, proxyPort);
Proxy proxy = new Proxy(Proxy.Type.HTTP, **addr**);
Socket socket = new Socket(proxy);
socket.connect(new InetSocketAddress(address, port));

答案 8 :(得分:-1)

我正在使用Socks通过代理编写一个带有c ++的应用程序,这个工具帮了我很多忙,看看HERE