Пример компьютера для управления мобильным телефоном на основе Node и WebSocket

Node.js внешний интерфейс сервер WebSocket

1. Предпосылки

Некоторое время назад одноклассник из «Планеты знаний» попросил меня поделиться WebSocket, когда я был свободен.Если не учитывать основные детали уровня протокола, то в основном одно или два предложения могут прояснить ситуацию:

WebSocket построен на транспортном уровне TCP и опирается на протокол прикладного уровня HTTP, который, по-видимому, в основном компенсирует дефект протокола HTTP, заключающийся в том, что сервер не может активно отправлять сообщения клиенту.

Но просто так отвечать, я не думаю, что это очень полезно для одноклассника, лучше воплотить это в жизнь и построить реальный пример.

实例效果
эффект экземпляра

Пример описания: Мобильный телефон может установить связь с компьютером путем сканирования QR-кода компьютера (на самом деле это не обязательно должен быть мобильный телефон для управления компьютером, если он является сквозным), а затем щелкните квадрат на мобильном телефоне, чтобы синхронно управлять квадратом на компьютере.
Пример опыта:портал

Во-вторых, реализация идей

用例图
диаграмма вариантов использования

  1. Сначала сторона ПК должна установить соединение со стороной сервера.После установления соединения сервер создает уникальный идентификатор для подключенного экземпляра и возвращает его клиенту. В то же время сохраняется карта для сохранения экземпляра соединения с идентификатором соединения в качестве значения ключа.
  2. Сторона ПК получает идентификатор соединения, объединяет URL-адрес страницы контроллера с идентификатором в качестве параметра и генерирует URL-адрес в виде QR-кода, что удобно для сканирования мобильного телефона.
  3. Мобильный телефон сканирует код для доступа к объединенному URL-адресу на стороне ПК, получает идентификатор связанной стороны из параметра URL-адреса и инициирует соединение с сервером.Когда соединение успешно установлено, связанный идентификатор отправляется на службы, сервер получает соответствующее сообщение и поддерживает карту для создания нового идентификатора экземпляра.Отношения с идентификатором связанной стороны
  4. Когда мобильный терминал нажимает на поле, он отправляет сообщение на сервер, и сервер находит экземпляр связанной стороны и прозрачно передает сообщение на ПК-терминал.
  5. Сторона ПК выполняет соответствующие действия согласно прозрачному сообщению

3. Реализация кода

1) Серверный код

Создайте службу WebSocket с помощью экспресс

const app = express();

// 创建应用服务器
const server = http.createServer(app);
// 启动 HTTP 服务
server.listen(port, '0.0.0.0', function onStart(err) {
    if (err) {
        console.log(err);
    }
    console.log('启动成功');
});

// 通过 ws 模块建立 Websocket 服务器
const WebSocketServer = require('ws').Server;
const wss = new WebSocketServer( { server : server } );

// 连接实例 Map
process.wsMap = {}
// 连接实例关联关系 Map
process.wsRelaMap = {}
// 连接监听
require('./src/socket/conn.js')(wss)

Для удобства здесь используется модуль узла ws, специально разработанный для работы с WebSocket.Как упоминалось ранее, WebSocket зависит от HTTP, поэтому при установке сервера WebSocket необходимо передать экземпляр HTTP-сервера. После того, как сервер успешно установлен, ему необходимо прослушивать подключения от клиента:

wss.on('connection', function( ws ) {
        // 连接实例 id
        const id = ws._ultron.id;
        ws.on('message', function( data, flags ) {
            const dataStr = data;
            data = JSON.parse(data);
            /**
            * 初始连接,并且传入了需要关联的 id
            */
            if (data.type === '1' && data.relaId) {
                wsRelaMap[id] = data.relaId;
            } else if (data.type === '2') { // 发送消息到关联方
                const rela = wsMap[wsRelaMap[id]];
                if (rela) {
                    rela.send(dataStr);
                }
            }
        });
        // 连接关闭,从 Map 中移除,否则长期占据内存
        ws.on('close', function() {
            console.log('stopping client');
            delete wsMap[id]
        });

       // 保持连接实例
        wsMap[id] = ws;
       // 发送 id 到客户端
        ws.send(message.buildConnectMessage(id));
    });

Тип сообщения различается в зависимости от типа соединения.Для начального сообщения о соединении тип равен 1. Если передается идентификатор связанной стороны, это устанавливает отношение ассоциации. Когда тип равен 2, найдите связанную сторону экземпляра и прозрачно передайте сообщение связанной стороне.

2) Код на стороне ПК (контролируемая сторона)

установить соединение

   var domain = '192.168.1.102:5001/';
   var wsServer = 'ws://' + domain;
   var websocket = new WebSocket(wsServer);

получить сообщение

function onMessage (evt) {
        // console.log(evt.data)
        // document.getElementById('message').innerText = evt.data
        var msg = JSON.parse(evt.data);
        var qrcodeImg = document.getElementById('qrcodeImg');
        console.log(msg);
        console.log(msg.id);
        // 消息类型为1,初始化连接的时候,服务器端返回连接 id
        if (msg.type === '1') {
            // 拼接控制方连接,并调用接口生成二维码
            qrcodeImg.src = 'http://qr.liantu.com/api.php?text=http://' + domain + 'handler.html?id=' + msg.id
        } else {
            // 其它类型的消息为控制消息,根据消息做相应的变换
            qrcodeImg.style.display = 'none';
            document.getElementById('show').style.display = 'block';
            if (msg.selected) {
                var items = document.getElementsByClassName('item');
                for (var i=0; i <items.length; i++) {
                    items[i].style.backgroundColor = '#ccc'
                }
                document.getElementById(msg.selected).style.backgroundColor = 'red'
            }
        }
    }

Когда начальное соединение установлено, сервер вернет идентификатор экземпляра соединения (отличите тип сообщения в соответствии с полем типа), а внешний интерфейс соединит ссылку контроллера в соответствии с идентификатором и вызовет интерфейс для генерации QR-кода. . Для управляющих сообщений после разбора достаточно изменить цвет соответствующего квадрата.

3) Интерфейсный контроллер

После того, как соединение будет открыто, получите идентификатор ассоциации из URL-адреса, отправьте его на сервер для установления ассоциации и прослушивания кликов по сетке и отправьте управляющее сообщение на сервер в любое время.

function onOpen () {
       // 获取关联 id
        var relaId = getQueryString('id') || 1
        var message = {
            type: '1',
            relaId: relaId
        };
      // 发起关联消息
        websocket.send(JSON.stringify(message));
        var conMsg = {
            type: '2',
            message: 'connected'
        };
        websocket.send(JSON.stringify(conMsg));

        // 监听点击,改变方格颜色,并发起控制消息
        var items = document.getElementsByClassName('item');
        for (var i=0; i <items.length; i++) {
            items[i].addEventListener('click', function (e) {
               var msg = {
                    type: '2',
                    selected: this.id
                };
                websocket.send(JSON.stringify(msg));
                for (var i=0; i <items.length; i++) {
                    items[i].style.backgroundColor = '#ccc';
                }
                this.style.backgroundColor = 'red';
            });
        }
    }

4. Резюме

Для конечной цели этот пример слишком прост, мы можем сделать и более крутые вещи, например: цветы перекатываются с мобильного телефона А на мобильный телефон Б, только вы не можете придумать, нет ничего, что мы не могли бы попробовать ~~

мы вПланета знаний Fima Front-endЗапущен план совместного строительства демонстраций WebSocket, искренне приглашаем вас присоединиться и летать вместе

菲麦前端,一个让知识深入原理的星球
Fima Front-end, планета, позволяющая знаниям углубиться в принцип