Проект отказывается от рукопожатия при использовании библиотеки java-websocket для подключения к потоку websocket для обмена монетами
Я пытаюсь использовать Java-Websocket-библиотеку TooTallNate для создания клиента websocket, который получает сообщения от поток обмена монетами обмена монетами. Я переношу программу, написанную на Python на Java, из-за параллельных узких мест в Python, и, насколько мне известно, я делаю то же самое на Java, как и в Python. Вот мой код, чтобы открыть соединение в Python с помощью this websocket lib (это работает как ожидалось):
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 [email protected] refuses handshake
Нет никакой аутентификации или чего-либо подобного для этого соединения, насколько я знаю (я не предоставлял ни одного в моей программе Python), поэтому я не понимаю, что это за источник этой ошибки.
Ответы
Ответ 1
Вам нужно создать 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());
Ответ 2
Вам нужно вызвать метод setSocket()
, прежде чем делать connect()
, например:
private CoinbaseWebsocketClient(URI serverURI) {
super(serverURI, new Draft_17());
setSocket(SSLSocketFactory.getDefault().createSocket(serverURI.getHost(), serverURI.getPort()));
connect();
}
Удачи!
Примечание. Остерегайтесь того, что ваш singleton get()
может не быть хорошей идеей в случае каких-либо сбоев (если я правильно помню, что класс клиента неприменим после неустранимой ошибки, и вам нужно создать новый клиент для восстановления).
Ответ 3
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/