使用java-websocket库连接到coinbase交易所websocket流时,草案拒绝握手

15
我正在尝试使用TooTallNate的Java-Websocket库创建一个websocket客户端,以从coinbase交易所websocket流接收消息。由于Python中存在并行化瓶颈,并且据我所知,我在Java中做的事情与Python中相同,因此我正在将自己编写的程序从Python移植到Java。以下是我在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时,我会收到以下错误:

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

据我所知,这个连接没有任何身份验证或类似的东西(我在我的Python程序中没有提供任何身份验证),所以我不知道这个错误的来源。


你尝试过将SocketFactory设置为接受所有SSL证书吗?这就是我(通过hack方法)解决wss问题的方式。 - samczsun
3个回答

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());

这不是问题的答案。如果您需要帮助,请发布一个新问题。 - Juan Cruz Soler
它应该是一个新的问题,而不是一个评论。但如果你想评论,请等到你有15个声望。 - Juan Cruz Soler
添加并回答,希望对你有所帮助。 - Prakash
这解决了我的问题,但答案有点混乱。我提交了一份编辑,进行了一些格式上的微调和实现说明。 - ndm13

0

在执行 connect() 前,您需要先调用 setSocket() 方法,例如:

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

祝你好运!


注意:请注意,如果出现任何故障,您的单例get()可能不是一个好主意(如果我记得正确,客户端类在无法恢复的错误后无法使用,您必须创建一个新的客户端来恢复)。

0

vlp 差不多是对的。但应该将 443 编码为端口参数:

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

对我来说这很有效!

附注:SSL 必须是有效的证书,否则您不能仅使用 getDefault 方法获取 SSL 上下文。对于自签名等,请参考以下链接:

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接