Проект отказывается от рукопожатия при использовании библиотеки java-websocket для подключения к потоку веб-сокетов обмена coinbase

Я пытаюсь использовать библиотеку Java-Websocket от TooTallNate для создания клиента веб-сокета, который получает сообщения от поток веб-сокетов биржи coinbase. Я переношу программу, написанную на Python, на Java из-за узких мест параллелизма в Python, и, насколько мне известно, на Java я делаю то же самое, что и на Python. Вот мой код для открытия соединения в Python с использованием этой библиотеки websocket (работает, как и ожидалось):

ws = websocket.create_connection("wss://ws-feed.exchange.coinbase.com", 20)
            ws.send(json.dumps({
            "type": "subscribe",
            "product_id": "BTC-USD"
        }))

Вот весь мой класс Java:

public class CoinbaseWebsocketClient extends WebSocketClient {

private final Gson gson = new Gson();

private CoinbaseWebsocketClient(URI serverURI) {
    super(serverURI, new Draft_17());
    connect();
}

private static URI uri;
private static CoinbaseWebsocketClient coinbaseWebsocketClient;

static {
    try {
        uri = new URI("wss://ws-feed.exchange.coinbase.com");
    } catch (URISyntaxException e) {
        e.printStackTrace();
    }
}

protected static CoinbaseWebsocketClient get() {
    if (coinbaseWebsocketClient == null) {
        coinbaseWebsocketClient = new CoinbaseWebsocketClient(uri);
    }
    return coinbaseWebsocketClient;
}

@Override
public void onOpen(ServerHandshake serverHandshake) {
    System.out.println("Websocket open");
    final JsonObject btcUSD_Request = new JsonObject();
    btcUSD_Request.addProperty("type", "subscribe");
    btcUSD_Request.addProperty("product_id", "BTC_USD");
    final String requestString = gson.toJson(btcUSD_Request);
    send(requestString);
}

@Override
public void onMessage(String s) {
    System.out.println("Message received: " + s);
}

@Override
public void onClose(int code, String reason, boolean remote) {
    System.out.println("Websocket closed: " + reason);
}

@Override
public void onError(Exception e) {
    System.err.println("an error occurred:" + e);
}

}

Я знаю, что в моем Java-коде нет принципиальной проблемы, потому что он работает, как и ожидалось, когда я использую ws://echo.websocket.org в качестве URI вместо wss://ws-feed.exchange.coinbase.com. Однако, когда я пытаюсь подключиться к wss://ws-feed.exchange.coinbase.com, я получаю эту ошибку:

Websocket closed: draft org.java_websocket.drafts.Draft_17@7ca2fefb refuses handshake

Насколько я знаю, для этого соединения нет аутентификации или чего-то подобного (я не предоставил ничего в своей программе Python), поэтому я не понимаю, каков источник этой ошибки.


person zjuhasz    schedule 06.01.2016    source источник
comment
Вы пытались настроить SocketFactory для приема всех сертификатов SSL? Вот как я (хакерски) исправил свою проблему с wss   -  person Sam Sun    schedule 08.01.2016


Ответы (3)


Необходимо создать sslcontext, как показано ниже. он пропускает сертификат. Мне удалось установить соединение без сертификата

SSLContext sslContext = SSLContext.getInstance("SSL");

// set up a TrustManager that trusts everything
sslContext.init(null, new TrustManager[] { new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
                    System.out.println("getAcceptedIssuers =============");
                    return null;
            }

            public void checkClientTrusted(X509Certificate[] certs,
                            String authType) {
                    System.out.println("checkClientTrusted =============");
            }

            public void checkServerTrusted(X509Certificate[] certs,
                            String authType) {
                    System.out.println("checkServerTrusted =============");
            }
} }, new SecureRandom());
person Prakash    schedule 17.06.2016
comment
Это не ответ на вопрос. Если вам нужна помощь, опубликуйте новый вопрос - person Juan Cruz Soler; 17.06.2016
comment
Это должен быть новый вопрос, а не комментарий. Но если вы хотите прокомментировать, подождите, пока у вас не будет 15 повторений. - person Juan Cruz Soler; 17.06.2016
comment
Добавьте и ответьте, надеюсь, это поможет - person Prakash; 18.06.2016
comment
Это решило мою проблему, но ответ был запутанным. Я отправил редактирование с некоторыми настройками форматирования и примечанием о реализации. - person ndm13; 09.02.2017

Вам нужно вызвать setSocket() перед выполнением connect(), например:

private CoinbaseWebsocketClient(URI serverURI) {
    super(serverURI, new Draft_17());
    setSocket(SSLSocketFactory.getDefault().createSocket(serverURI.getHost(), serverURI.getPort()));
    connect();
}

Удачи!


Примечание: имейте в виду, что ваш singleton get() может быть не очень хорошей идеей в случае каких-либо сбоев (если я правильно помню, клиентский класс непригоден для использования после неисправимой ошибки, и вам нужно создать новый клиент для восстановления).

person vlp    schedule 17.01.2016

vlp почти прав. Но следует жестко закодировать 443 в качестве параметра порта:

private CoinbaseWebsocketClient(URI serverURI) {
    super(serverURI, new Draft_17());
    setSocket(SSLSocketFactory.getDefault().createSocket(serverURI.getHost(), 443));
    connect();
}

Это подходит для меня!

PS. ssl должен быть действительным сертификатом, иначе вы не сможете просто использовать метод getDefault для получения контекста ssl. Для самоподпаленных и т. д. перейдите по следующей ссылке:

http://blog.antoine.li/2010/10/22/android-trusting-ssl-certificates/

person Sam Shaw    schedule 07.12.2016