Подтвердить что ты не робот

Как подключить сервер Socket через HTTP-прокси

У меня есть часть кода для подключения к серверу 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));

этот пост предполагает, что я должен использовать Jakarta Commons HttpClient, но как использовать его для подключения Socket-сервера через HTTP-прокси?

ОБНОВЛЕНО: Я использовал SOCKS proxy, и он не работает, если я использую 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)
4b9b3361

Ответ 1

Вы можете попробовать JHttpTunnel, хотя для этого вам нужно программное обеспечение, работающее по обе стороны туннеля.

Ответ 2

Это ссылка, которую я опубликовал ранее:

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

Помните, что этот новый прокси-объект представляет собой определение прокси-сервера, не более того. Как мы используем такой объект? Новый новый метод openConnection() был добавлен в класс URL и принимает прокси в качестве аргумента, он работает так же, как openConnection() без аргументов, за исключением того, что он заставляет соединение быть установленным через указанный прокси, игнорируя все остальные настройки, включая упомянутые выше свойства системы.

Итак, завершая предыдущий пример, теперь мы можем добавить:

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

Это ссылка, которую я опубликовал ранее. Я на iPad, поэтому не могу правильно отформатировать его.

Можете ли вы сделать это так? Я вижу, что вы делаете сокеты напрямую, но вы делаете http, поэтому, возможно, так делаете?

Ответ 3

Я создал небольшой класс Socket Factory для обработки 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/

Ответ 4

Согласно Wikipedia на HTTP-туннелирование, важная вещь про HTTP-прокси заключается в том, что он проксирует HTTP-протокол.

Итак, если у вас есть сервер и клиент и вы хотите, чтобы они связывались через прокси-сервер HTTP, то и сервер, и клиент должны быть изменены для передачи протокола HTTP.

В качестве альтернативы вам потребуется дополнительное программное обеспечение, которое может реализовать VPN через HTTP, например OpenVPN.

Изменить: Исключением является поддержка некоторых прокси-серверов HTTP и включение метода HTTP CONNECT, который после базовый процесс настройки через HTTP позволяет создавать и маршрутизировать обычный TCP-сокет. Это позволяет подключаться к приложениям без тяжелой работы полного преобразования в HTTP-туннелирование. Хорошим примером этого является MSN Messenger. Однако, как отмечается в статьях Википедии, эта функция часто отключается или даже не поддерживается по соображениям безопасности.

Ответ 5

Похоже, вы запрашиваете прокси-сервер SOCKS, который отличается от прокси-сервера HTTP. Возможно, попробуйте Proxy.Type.HTTP.

Вопрос: ваш клиент основан на HTTP? Я не уверен, что это сработает, если ваш клиент не говорит HTTP.

Ответ 6

Правильно ли я говорю, что вы хотите использовать HTTP-прокси (для примера squid), чтобы установить метод 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, особенно кодом ответа, будет обработано.

Ответ 7

Ну, вы можете управлять прокси-сервером, задав требуемый URL-адрес сразу после URL-адреса прокси-сервера или используя URL-адрес Java следующим образом:

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

С помощью этого вы создаете URL-адрес, например http://ProxyHost:ProxyPorthttp://destinationAddress, поэтому вам не нужно устанавливать экземпляр класса Proxy на Java, который, скорее всего, выдает указанное исключение:

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 Type Type, если вы хотите установить прокси-сервер.

Ответ 8

Я использую приложение с С++, используя Socks через прокси, этот инструмент мне очень помогает, посмотрите ЗДЕСЬ