我正在尝试使用Java-Websocket library by TooTallNate创建一个websocket客户端,它接收来自coinbase exchange websocket stream的消息。我正在将我用Python制作的程序移植到Java中,因为Python中存在并行化瓶颈,据我所知,我在Java中做的事情与在Python中做的相同。这是我使用this websocket lib在Python中打开连接的代码(这可以按预期工作):
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而不是wws://ws-feed.exchange时,它按预期工作。 coinbase.com。但是,当我尝试连接到wss://ws-feed.exchange.coinbase.com时,我收到此错误:
Websocket closed: draft org.java_websocket.drafts.Draft_17@7ca2fefb refuses handshake
据我所知,没有任何身份验证或类似的连接(我没有在我的Python程序中提供任何内容)所以我不知道这个错误的来源是什么
答案 0 :(得分: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());
答案 1 :(得分:0)
您需要在执行private CoinbaseWebsocketClient(URI serverURI) {
super(serverURI, new Draft_17());
setSocket(SSLSocketFactory.getDefault().createSocket(serverURI.getHost(), serverURI.getPort()));
connect();
}
之前调用setSocket()
方法,例如:
get()
祝你好运!
注意:请注意,如果出现任何故障,您的单件{{1}}可能不是一个好主意(如果我记得正确的话,客户端类在不可恢复的错误后无法使用,并且您必须创建一个新的客户端来恢复)
答案 2 :(得分:0)
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/