Как подключить сокет сервер через HTTP прокси - PullRequest
14 голосов
/ 29 августа 2011

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

Ответы [ 8 ]

4 голосов
/ 08 апреля 2013

Я создал небольшой класс Socket Factory для обработки HTTP-соединения через сокет. Затем сокет можно использовать как обычно, если прокси-сервер поддерживает 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 /312477/dekodirovat-dannye-base64-v-java#312491
     */
    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/

2 голосов
/ 29 августа 2011

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

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, так что, может быть, вы поступите так?

2 голосов
/ 29 августа 2011

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

0 голосов
/ 25 февраля 2014

Я пишу приложение на c ++, используя Socks через Proxy. Этот инструмент мне очень помогает, посмотрите ЗДЕСЬ

0 голосов
/ 13 марта 2013

Итак, вы можете управлять прокси-сервером, установив запрошенный 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, если вы устанавливаете прокси такого типа.

0 голосов
/ 26 сентября 2011

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

0 голосов
/ 29 августа 2011

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

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

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

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

0 голосов
/ 29 августа 2011

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...