目的

学习 websocket

基础知识

  1. 了解 maven,能新建 maven 工程
  2. 熟悉 java
  3. 了解 html 及 javascript

pom 依赖

<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>3.8.0</version>
</dependency>
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>mockwebserver</artifactId>
    <version>3.8.0</version>
</dependency>                   

Websocket server for pc

package com.carl.websocketdemo;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import okhttp3.Response;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;

public class WebsocketServer {
    public final static MockWebServer mockWebServer = new MockWebServer();
    public static boolean isConnected = false;
    public static final ExecutorService writeExecutor = Executors.newSingleThreadExecutor();

    public static void createWebsocket() {
        mockWebServer.enqueue(new MockResponse().withWebSocketUpgrade(new WebSocketListener() {
            WebSocket webSocketServer = null;

            public void onClose(WebSocket webSocket, int code, String reason) {
                System.out.println("server onClose");
                createWebsocket();//如果服务端关闭,则重新建立websocket server
            }

            public void onFailure(WebSocket webSocket, Throwable t, Response response) {
                System.out.println("server onFailure");
                        System.out.println("ioException:" + t.getMessage());
                        System.out.println("response:" + response);

                        isConnected = false;

                        this.onClose(webSocket, 1, t.getMessage());
            }

            public void onMessage(WebSocket webSocket, String text) {

                System.out.println("onMessage body:" + text);
                if ("start".equals(text)) {
                    //replay it
                    writeExecutor.execute(new Runnable() {

                        public void run() {
                            while(isConnected) {
                                try {
                                    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                                    webSocketServer.send(df.format(new Date()));
                                    Thread.sleep(1000);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    });
                }
            }

            public void onOpen(WebSocket webSocket, Response res) {

                this.webSocketServer = webSocket;

                System.out.println("server onOpen");
                isConnected = true;

            }

        }));
    }

    public static void main( String[] args ) {
        createWebsocket();

        try {
            //System.out.println(mockWebServer.getPort());

            mockWebServer.start(9990);
            System.out.println(mockWebServer.getPort());
            System.out.println(mockWebServer.getRequestCount());

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Websocket client for pc

package com.carl.websocketdemo;

import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;

public class WebsocketClient {

    static String hostName = WebsocketServer.mockWebServer.getHostName();
    static int port = 9991;
    static WebSocket webSocketClient = null;
    static int receiveTimeCount =0;

    public static void main(String[] args) {
        System.out.println("hostName:" + hostName);
        System.out.println("port:" + port);

        OkHttpClient client = new OkHttpClient.Builder().readTimeout(0, TimeUnit.MILLISECONDS).build(); 

        //构造request对象
        Request request = new Request.Builder().url("ws://" + hostName + ":" + port + "/").build();

        //new 一个websocket调用对象并建立连接
        client.newWebSocket(request, new WebSocketListener() {

            public void onOpen(final WebSocket webSocket, Response response) {
                //保存引用,用于后续操作
                //webSocketClient = webSocket;
                //打印一些内容
                System.out.println("client onOpen");

                //注意下面都是write线程回写给客户端
                //建立连接成功后,发生command 1给服务器端
                webSocket.send("start");

            }

            @Override
            public void onMessage(WebSocket webSocket, String message) {
                System.out.println("client onMessage " + receiveTimeCount + ", " + message);
                receiveTimeCount++;
            }

            public void onClose(WebSocket webSocket, int code, String reason) {
                System.out.println("client onClose");
                System.out.println("code:" + code + " reason:" + reason);

                System.exit(0);

            }

            public void onFailure(WebSocket webSocket, Throwable t, Response response) {
                //发生错误时会回调到这
                System.out.println("client onFailure");
                System.out.println("throwable info is: " + t);

                this.onClose(webSocket, 1, t.getMessage());
            }
        });
    }
}

Websocket server for android

package com.sn.websocketdemo;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import okhttp3.Response;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;

public class WebsocketServer {
    public MockWebServer mockWebServer = new MockWebServer();
    public boolean isConnected = false;
    public ExecutorService writeExecutor = Executors.newSingleThreadExecutor();

    public void createWebsocket() {
        mockWebServer.enqueue(new MockResponse().withWebSocketUpgrade(new WebSocketListener() {
            WebSocket webSocketServer = null;

            public void onClose(WebSocket webSocket, int code, String reason) {
                System.out.println("server onClose, code is:" + code + ", reason is:" + reason);
                createWebsocket();
            }

            public void onFailure(WebSocket webSocket, Throwable t, Response response) {
                System.out.println("server onFailure");
                System.out.println("ioException:" + t.getMessage());
                System.out.println("response:" + response);

                isConnected = false;

                this.onClose(webSocket, 1, t.getMessage());
            }

            public void onMessage(WebSocket webSocket, String text) {

                System.out.println("onMessage body:" + text);
                if ("start".equals(text)) {
                    //replay it
                    writeExecutor.execute(new Runnable() {

                        public void run() {
                            while(isConnected) {
                                try {
                                    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                                    webSocketServer.send(df.format(new Date()));
                                    Thread.sleep(1000);
                                    connectTimeout = defaultTimeout;
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    });
                }
            }

            public void onOpen(WebSocket webSocket, Response res) {

                this.webSocketServer = webSocket;

                System.out.println("server onOpen");
                isConnected = true;
                //System.out.println("server request header:" + res.request().headers());
                //System.out.println("server response header:" + res.headers());
                //System.out.println("server response:" + res);

            }

        }));
    }
}


package com.sn.websocketdemo;

import android.content.Context;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Looper;

import java.io.IOException;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;

public class WebsocketServerThread extends Thread { //在android中网络交互的动作需要放在一个独立的线程中,不能在主线程中进行网络交互
    private int port = 9991;
    private WebsocketServer ws;
    private Looper looper;
    boolean isRunning = false;

    WebsocketServerThread(int port) {
        this.port = port;

        ws = new WebsocketServer();
        ws.createWebsocket();
    }

    boolean isServerRunning() {
        return isRunning;
    }

    @Override
    public void run() {
//        Looper.prepare();
//        looper = Looper.myLooper();
        startServer();
//        Looper.loop();
    }

    public void startServer() {
//        if (isServerRunning()) {
//            return;
//        }

        try {
            System.out.println("WebsocketServerTest stat");

            String str = getHostIP();
            String[] ipStr = str.split("\\.");
            byte[] ipBuf = new byte[4];
            for(int i = 0; i < 4; i++){
                ipBuf[i] = (byte)(Integer.parseInt(ipStr[i])&0xff);
            }

            InetAddress inetAddress = InetAddress.getByAddress(ipBuf);

            ws.mockWebServer.start(inetAddress, 9991);
            isRunning = true;
            System.out.println("WebsocketServerTest stat:" + ws.mockWebServer.getPort());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static String getHostIP() {

        String hostIp = null;
        try {
            Enumeration nis = NetworkInterface.getNetworkInterfaces();
            InetAddress ia = null;
            while (nis.hasMoreElements()) {
                NetworkInterface ni = (NetworkInterface) nis.nextElement();
                Enumeration<InetAddress> ias = ni.getInetAddresses();
                while (ias.hasMoreElements()) {
                    ia = ias.nextElement();
                    if (ia instanceof Inet6Address) {
                        continue;// skip ipv6
                    }
                    String ip = ia.getHostAddress();
                    if (!"127.0.0.1".equals(ip)) {
                        hostIp = ia.getHostAddress();
                        break;
                    }
                }
            }
        } catch (SocketException e) {
            e.printStackTrace();
        }
        return hostIp;

    }
}

Websocket client with javascript

<!DOCTYPE html>  
<meta charset="utf-8" />  
<title>WebSocket Test</title>  
<script language="javascript"type="text/javascript">

    function createWebSocket() {
        websocket = new WebSocket('ws://10.**.**.**:9991/');
        console.log("websocket.readyState before onopen:" + websocket.readyState);

        websocket.onopen = function() {
          console.log("websocket.readyState:" + websocket.readyState);
          websocket.send('start');
        }

        websocket.onclose = function(message) {
          console.log('onclose', message);
          //sleep(1000);
        }

        websocket.onerror = function(message) {
          console.log('onerror', message.data);

        }

        websocket.onmessage = function(message) { 
            console.log(message.data);
            document.getElementById("showTime").innerHTML = message.data;
        }
    }

    function closeWebSocket() {  
        websocket.close();  
    }

    window.onbeforeunload = function () {  
       closeWebSocket();
    }

    window.onload = function() {
        //console.log("websocket.readyState onload:" + websocket.readyState);
        createWebSocket();
    };

</script>  
<h2>WebSocket Test</h2>  
<h2 id="showTime">show time</h2>
</html>

问题

  1. 参考 appium 源码中的 uiautomatorserver 代码,暂时不明白 Looper 的作用
  2. 打开本地的 html 页面后,能正常展示服务端的时间,但是在刷新页面的时候,会造成异常,暂未解决,本人想到的解决思路大概有两种: a. 在刷新页面之前,判断 websocket 连接状态,如果已存在连接则关闭,在页面刷新完成后重新创建连接 b. 在刷新页面后返回原来的连接

其他应用举例

stf 中获取手机屏幕


↙↙↙阅读原文可查看相关链接,并与作者交流