寫在前面
之前接觸過一個Android小項目,其中有個功能是服務端將文件推送到客戶端,那時候,是通過客戶端的輪詢去詢問是否有文件推送,如果有,則進行文件下載。其實,這種做法不可取,可以用Websocket來實現一個簡單的消息推送系統,用於替代輪詢。
Websocket Server
在這個 server demo中,使用的是GitHub上面的一個開源項目Java-WebSocket
-
在AndroidStudio中添加依賴:
implementation ‘org.java-websocket:Java-WebSocket:1.3.9’
-
創建Server類:
public class WsServer extends WebSocketServer { public WsServer(int port, SSLContext sslContext) { super(new InetSocketAddress(port)); this.setWebSocketFactory(new DefaultSSLWebSocketServerFactory(sslContext)); } @Override public void onOpen(WebSocket conn, ClientHandshake handshake) { //This method sends a message to the new client conn.send("Welcome to the server!"); broadcast("new connection: " + handshake.getResourceDescriptor()); //This method sends a message to all // clients connected System.out.println( conn.getRemoteSocketAddress().getAddress().getHostAddress() + " entered the room!"); } @Override public void onClose(WebSocket conn, int code, String reason, boolean remote) { broadcast(conn + " has left the room!"); System.out.println(conn + " has left the room!"); } @Override public void onMessage(WebSocket conn, String message) { broadcast(message); System.out.println(conn + ": " + message); } @Override public void onMessage(WebSocket conn, ByteBuffer message) { broadcast(message.array()); System.out.println(conn + ": " + message); } @Override public void onError(WebSocket conn, Exception ex) { ex.printStackTrace(); if (conn != null) { // some errors like port binding failed may not be assignable to a specific websocket } } @Override public void onStart() { System.out.println("Server started!"); setConnectionLostTimeout(0); setConnectionLostTimeout(100); } }
-
開啓Websocket Server
private void startServer() { if (mWsServer != null) { try { mWsServer.stop(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } mWsServer = new WsServer(8888, makeSSLContext()); mWsServer.start(); }
WebSocket Client
客戶端的實現,可以直接使用Java-WebSocket庫的Client,可以參考這個項目中的examples,但在本示例中,我是使用OkHttp的Websocket來實現客戶端。
-
創建客戶端項目,並依賴OkHttp
-
創建OKHttpClient
private void initClient() { CustomTrust ct = new CustomTrust(); client = new OkHttpClient.Builder() .sslSocketFactory(ct.sslSocketFactory, ct.trustManager) .hostnameVerifier(hostnameVerifier) .build(); }
-
連接遠端服務器
private void connectWs() { if (mWebSocket != null) { mWebSocket.cancel(); mListener = null; } Request.Builder builder = new Request.Builder(); // wss : support ssl // Both server and client can run in a same device, so the ip can be set to localhost builder.url("wss://localhost:8888"); Request request = builder.build(); mListener = new WsSocketListener(); mWebSocket = client.newWebSocket(request, mListener); }