基於Web實現遠端與硬體互動

_DangJin發表於2019-02-16

基於Web實現遠端與硬體互動

專案背景:

最近在做一個類似“速遞櫃”的專案,專案需求大概如下:
1.使用者使用微信掃描二維碼
2.後臺匹配相關資料,並儲存使用者資訊,最終返回給使用者當前櫃子當前狀態
3.使用者選擇“開櫃”指令,進行存取物品

需求分析

1.實現跟硬體進行資料互動,使用TCP/IP 長連線,意味著,我們要有一個TCP伺服器,TCP伺服器一方面接受使用者發過來的相關請求指令,另一方面完成傳送指令給指定硬體這一操作。
2.除了TCP 伺服器我們還需要一個 Websocket 伺服器,也有兩個功能,一方面接受客戶端傳送的指令,另一方面處理轉發使用者指令給TCP伺服器。

功能實現

TCP 伺服器,Websocket 伺服器 使用相對成熟的 Workman 實現。

Workerman是一款純PHP開發的開源高效能的PHP socket 伺服器框架。被廣泛的用於手機app、移動通訊,微信小程式,手遊服務端、網路遊戲、PHP聊天室、硬體通訊、智慧家居、車聯網、物聯網等領域的開發。 支援TCP長連線,支援Websocket、HTTP等協議,支援自定義協議。擁有非同步Mysql、非同步Redis、非同步Http、非同步訊息佇列等眾多高效能元件。

GatewayWorker 目錄結構

├── Applications // 這裡是所有開發者應用專案
│   └── YourApp  // 其中一個專案目錄,目錄名可以自定義
│       ├── Events.php // 開發者只需要關注這個檔案
│       ├── start_gateway.php // gateway程式啟動指令碼,包括埠號等設定
│       ├── start_businessworker.php // businessWorker程式啟動指令碼
│       └── start_register.php // 註冊服務啟動指令碼
│
├── start.php // 全域性啟動指令碼,此指令碼會依次載入Applications/專案/start_*.php啟動指令碼
│
└── vendor    // GatewayWorker框架和Workerman框架原始碼目錄,此目錄開發者不用關心
  1. 首先我們 Applications 複製兩份 YourApp 目錄下的檔案,此時我們的目錄結構應該是這樣的
├── Applications // 這裡是所有開發者應用專案
│   └── TcpServer  // 其中一個專案目錄,目錄名可以自定義
│       ├── Events.php // 開發者只需要關注這個檔案
│       ├── start_gateway.php // gateway程式啟動指令碼,包括埠號等設定
│       ├── start_businessworker.php // businessWorker程式啟動指令碼
│       └── start_register.php // 註冊服務啟動指令碼
│   └── WSServer  
│       ├── Events.php 
│       ├── start_gateway.php 
│       ├── start_businessworker.php 
│       └── start_register.php 
│
├── start.php // 全域性啟動指令碼,此指令碼會依次載入Applications/專案/start_*.php啟動指令碼
│
└── vendor    // GatewayWorker框架和Workerman框架原始碼目錄,此目錄開發者不用關心
  1. 修改以及配置 TCPServerstart_register.php 下我們不做任何修改,但需要注意的是register 必須是text協議
// register 必須是text協議
$register = new Register(`text://0.0.0.0:1238`);

2.修改 start_gateway.php

// gateway 程式,這裡使用 TCP 協議,可以用telnet測試
$gateway = new Gateway("tcp://0.0.0.0:8282");
// gateway名稱,status方便檢視
$gateway->name = `TcpGateway`;
// gateway程式數
$gateway->count = 4;
// 本機ip,分散式部署時使用內網ip
$gateway->lanIp = `127.0.0.1`;
// 內部通訊起始埠,假如$gateway->count=4,起始埠為4000
// 則一般會使用4000 4001 4002 4003 4個埠作為內部通訊埠 
$gateway->startPort = 2900;
// 服務註冊地址
$gateway->registerAddress = `127.0.0.1:1238`;

3.修改 start_businessworker.php

// bussinessWorker 程式
$worker = new BusinessWorker();
// worker名稱
$worker->name = `TcpBusinessWorker`;
// bussinessWorker程式數量
$worker->count = 4;
// 服務註冊地址
$worker->registerAddress = `127.0.0.1:1238`;

4.根據上面的操作,我們修改WSServer目錄下的檔案,這個修改跟上面一樣的,但是要注意的是,兩個應用應該是不用的埠,所以需要修改的地方有兩個,start_gateway下的埠,還有start_register埠。!!!! 兩個應用下register 和 Gateway 埠一定不一致!!!

好了,到目前為止,我們已經完成了兩個伺服器的建立,那麼我們兩個伺服器之間如何資料共享呢?答案很簡單,我們在ws服務下建立一個tcp 客戶端即可,讓tcp 客戶端與我們tcp 伺服器連線就可以,然後通過tcp 客戶端直接傳送相關資料給tcp伺服器就可以,當然並不是所有資料都是通過這樣的方式共享的,我們其他資訊還是通過共用一個資料庫來共享的。相關程式碼如下:

  public static function onConnect($client_id)
    {
        // 向所有人傳送
        $host = "127.0.0.1";
        $port = 8282;
        global $socket;
        if (empty($socket)) {
            $socket = TcpClient::getInstace()->connect($host, $port);
        Gateway::sendToClient($client_id, "$client_id welcome

");
        }
    }


    public static function onMessage($client_id, $message)
    {
        if ($GLOBALS[`socket`]) {
            // 資料指令解包
            $message_arr = str_split(str_replace(` `, ``, trim($message)), 2);
            $cmd=null;
            for ($j = 0; $j < count($message_arr); $j++) {
                //socket_write($GLOBALS[`socket`], bin2hex($message_arr[$j]));
                socket_write($GLOBALS[`socket`],chr(hexdec($message_arr[$j])));
            }
        }
    }

好了,截止目前我們就完成了服務端工作,當然客戶端只是簡單的建立一個ws連線就好。

相關文章