websocket
WebSocketConnection 是在application#oncreate的时候就开启了,但是只有在手机号验证完成登录成功后才能连接成功。
2021-04-09 15:19:38.742 5902-6373/org.thoughtcrime.securesms I/WebSocketConnection: connect()
2021-04-09 15:19:38.758 5902-6373/org.thoughtcrime.securesms I/ApplicationDependencyPr: onConnecting()
2021-04-09 15:19:39.414 5902-6394/org.thoughtcrime.securesms W/WebSocketConnection: onFailure()
java.net.ProtocolException: Expected HTTP 101 response but was '403 Forbidden'
at okhttp3.internal.ws.RealWebSocket.checkResponse(RealWebSocket.java:229)
at okhttp3.internal.ws.RealWebSocket$2.onResponse(RealWebSocket.java:196)
at okhttp3.RealCall$AsyncCall.execute(RealCall.java:203)
at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
2021-04-09 15:19:39.414 5902-6394/org.thoughtcrime.securesms W/ApplicationDependencyPr: onAuthenticationFailure()
2021-04-09 15:19:39.414 5902-6394/org.thoughtcrime.securesms D/EventBus: No subscribers registered for event class org.thoughtcrime.securesms.events.ReminderUpdateEvent
2021-04-09 15:19:39.414 5902-6394/org.thoughtcrime.securesms D/EventBus: No subscribers registered for event class org.greenrobot.eventbus.NoSubscriberEvent
2021-04-09 15:19:39.414 5902-6394/org.thoughtcrime.securesms I/WebSocketConnection: onClose()
2021-04-09 15:19:39.414 5902-6394/org.thoughtcrime.securesms W/ApplicationDependencyPr: onDisconnected()
2021-04-09 15:19:43.629 5902-5976/org.thoughtcrime.securesms W/WebsocketStrategy: Websocket timeout. (1140030 ms elapsed)
2021-04-09 15:19:54.415 5902-6394/org.thoughtcrime.securesms I/WebSocketConnection: connect()
2021-04-09 15:19:54.421 5902-6394/org.thoughtcrime.securesms I/ApplicationDependencyPr: onConnecting()
2021-04-09 15:19:55.056 5902-6396/org.thoughtcrime.securesms W/WebSocketConnection: onFailure()
java.net.ProtocolException: Expected HTTP 101 response but was '403 Forbidden'
at okhttp3.internal.ws.RealWebSocket.checkResponse(RealWebSocket.java:229)
at okhttp3.internal.ws.RealWebSocket$2.onResponse(RealWebSocket.java:196)
at okhttp3.RealCall$AsyncCall.execute(RealCall.java:203)
at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
2021-04-09 15:19:55.057 5902-6396/org.thoughtcrime.securesms W/ApplicationDependencyPr: onAuthenticationFailure()
2021-04-09 15:19:55.057 5902-6396/org.thoughtcrime.securesms D/EventBus: No subscribers registered for event class org.thoughtcrime.securesms.events.ReminderUpdateEvent
2021-04-09 15:19:55.058 5902-6396/org.thoughtcrime.securesms D/EventBus: No subscribers registered for event class org.greenrobot.eventbus.NoSubscriberEvent
2021-04-09 15:19:55.058 5902-6396/org.thoughtcrime.securesms I/WebSocketConnection: onClose()
2021-04-09 15:19:55.058 5902-6396/org.thoughtcrime.securesms W/ApplicationDependencyPr: onDisconnected()
websocket的心跳包机制
D/WebSocketConnection: Sending keep alive...
W/AlarmSleepTimer: Setting alarm to wake up in 55000ms.
//WebSocketConnection.java
...
private static final int KEEPALIVE_TIMEOUT_SECONDS = 55;
...
private class KeepAliveSender extends Thread {
private AtomicBoolean stop = new AtomicBoolean(false);
public void run() {
while (!stop.get()) {
try {
sleepTimer.sleep(TimeUnit.SECONDS.toMillis(KEEPALIVE_TIMEOUT_SECONDS));
Log.d(TAG, "Sending keep alive...");
sendKeepAlive();
} catch (Throwable e) {
Log.w(TAG, e);
}
}
}
public void shutdown() {
stop.set(true);
}
}
private synchronized void sendKeepAlive() throws IOException {
if (keepAliveSender != null && client != null) {
byte[] message = WebSocketMessage.newBuilder()
.setType(WebSocketMessage.Type.REQUEST)
.setRequest(WebSocketRequestMessage.newBuilder()
.setId(System.currentTimeMillis())
.setPath("/v1/keepalive")
.setVerb("GET")
.build()).build()
.toByteArray();
if (!client.send(ByteString.of(message))) {
throw new IOException("Write failed!");
}
}
}
...
有个发送心跳包的线程,每隔55秒会发送一个心跳包,发送的请求的path是/v1/keepalive
。
websocket的接口地址
目前项目中使用的发送接收消息的 websocket 的接口地址和后台接口地址是一样的,只是后面的path路径不一样。
WebSocketConnection的代码逻辑中会将https替换为wss,将http替换为ws,然后建立WebSocket连接。
//WebSocketConnection.java
public WebSocketConnection(String httpUri,
TrustStore trustStore,
Optional<CredentialsProvider> credentialsProvider,
String signalAgent,
ConnectivityListener listener,
SleepTimer timer,
List<Interceptor> interceptors,
Optional<Dns> dns)
{
this.trustStore = trustStore;
this.credentialsProvider = credentialsProvider;
this.signalAgent = signalAgent;
this.listener = listener;
this.sleepTimer = timer;
this.interceptors = interceptors;
this.dns = dns;
this.attempts = 0;
this.connected = false;
String uri = httpUri.replace("https://", "wss://").replace("http://", "ws://");
...
比如配置的地址是:http://192.168.1.1:80
,那么WebSocketConnection创建的时候会将地址替换为ws://192.168.1.1:80
,然后发起建立连接的请求。
nginx服务器需要支持wss
nginx服务器需要配置路由模块,这样才可以正常访问服务器上的ws/wss接口,否则只能访问http/https接口,访问ws/wss接口时在创建websocket时的握手阶段就会报错:404 not found
或者是 500 Server Error
等。
404 not found
500 Server Error
或者是 500 Server Error
:
W/WebSocketConnection: onFailure()
java.net.ProtocolException: Expected HTTP 101 response but was '500 Server Error'
at okhttp3.internal.ws.RealWebSocket.checkResponse(RealWebSocket.java:229)
at okhttp3.internal.ws.RealWebSocket$2.onResponse(RealWebSocket.java:196)
at okhttp3.RealCall$AsyncCall.execute(RealCall.java:203)
at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
服务器端代码报错:
403 Forbidden
如果服务器返回 403 Forbidden,说明客户端与websocket服务端是可以正常建立连接的,但是客户端认证失败:
securesms W/WebSocketConnection: onFailure()
java.net.ProtocolException: Expected HTTP 101 response but was '403 Forbidden'
at okhttp3.internal.ws.RealWebSocket.checkResponse(RealWebSocket.java:229)
at okhttp3.internal.ws.RealWebSocket$2.onResponse(RealWebSocket.java:196)
at okhttp3.RealCall$AsyncCall.execute(RealCall.java:203)
at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
参看:WebSocket: Expected HTTP 101 response but was ‘403 Forbidden‘
403 Forbidden 是websocket连接成功后,在认证过程中如果认证失败会返回的状态码。