在上一篇Laravel如何優雅的使用Swoole中我已經大概談到了Laravel結合Swoole的用法。今天,我參與的智能家居項目基本上已經結束了Web服務器及android端的開發(熬了個通宵突擊把剩下的做了,好累), 趁熱來聊聊基于Laravel+Swoole開發智能家居后端的關鍵技術點。
16進制ASCII碼協議的解析##
硬件我不談,我只需要關心數據解析。如何基于Swoole如果在php中解析16進制的ascii碼,這種文章還比較少呢。但核心的部分還是可以整理出來的,關鍵用到的就是chr()、hexdec()、bin2hex()這3個函數,網上還提到了用pack()、unpack(),因為前面3個函數以及很好的解決了問題,所以就沒有繼續深入。我建議在這里Php Manual官網先熟悉下這幾個函數。
chr()函數從不同的 ASCII 值返回字符,hexdec() 函數把十六進制轉換為十進制。通常結合這兩個函數把16進制字符串轉換為ASCII字符串,理解起來有點繞。
例如: echo chr(hexdec('fe'));//輸出的就是下位機能認識的16進制的FE,大小寫不敏感
bin2hex()函數把 ASCII 字符的字符串轉換為十六進制值,用于從Swoole中讀取數據的轉換。
例如:$buffer = str_split(bin2hex($data), 2);//$data是Swoole中OnReceive事件傳遞的值
在解析協議時,上例中的$buffer數組中,存放了協議的每一位。那么怎么解析呢?最快最懶的方法就是根據硬件研發的協議一位一位的去讀取數據,例如頭是第一位,那么就是$buffer[0];如果連著好幾位組合起來是數據,就寫個小函數拼。
是不是太弱雞了點(.NET和JAVA有很豐富的byte[]轉整形和字符串的方法集)?如果你需要,可以自己寫個轉換工具類出來(我暫時用不上就沒整理)。
在下位機通信中還有一個很重要的技術點就是XOR校驗,我是從stackoverflow找到的源碼,直接貼地址。
16進制ASCII碼協議的創建##
不廢話,直接上代碼:
對Laravel使用者,在這部分我強烈建議好好復習一下Laravel提供的快速數組函數輔助方法。
與硬件的曲線通信##
基于Swoole接收數據在上一篇中已經詳細介紹不再累述,這里主要說說向硬件發送數據的問題。上一篇中,我提到了2種方法,一種是利用fsockopen()函數;一種是內部端口監聽。這里還和搞硬件的大神鬧了個笑話,臉紅啊..對基于TCP/IP協議的通信,因為端口一直被接收監聽占用,所以用fsockopen()或者socket_write()函數是行不通的,必須基于第二種方式曲線實現硬件通信。
首先在Command中添加內部端口的監聽,注意onReceive事件被自定義的InnerHandler接收(不知所云者請復習上一篇以及Swoole的文檔)。一定記得在iptables中把你的內部監聽端口打開!!
在Innerhandler中,若接收到需要發送到硬件的命令(就是上一節說的數據),從緩存里面提取該硬件的連接實體,然后發送數據(不知所云請參考Swoole文檔)。這里比較曲線的情況就是在這個緩存,這個緩存是在需要發送數據的時候設定的,那么怎么知道硬件的連接實體是什么?當然是保持一個KV結構的數據啦:)
整個曲線的通信過程就是:當需要向硬件發送數據的時候,首先將數據發送到這個內部監聽端口來,然后再從這里發送到硬件去。怎么向內部監聽端口發送數據呢?用fsockopen()或者socket_write()都是完全沒問題的,這里的代碼就請自行搜索,權當練習,不要太懶了。
Event大有裨益##
這個要用過了才知道有多方便,來這里先好好復習一下。實現過程請自行感受,我就只說說我哪里用到了Event:
1.基于JPUSH推送消息
2.向內部監聽發送數據
另外只補充一點,想利用Event通過Swoole發送數據的路是行不通的。
優雅的快速測試##
由于PHP是弱類型,因此理解起來比較費解。接收數據和向硬件發送數據的數據類型是不一樣的。用bin2hex()得到的是形如"11 00 00 FE"的字符串,用chr(hexdec())得到的是16進制的ASCII碼,如果echo輸出的話,會是亂碼。那么如何測試(看到)自己生成的16進制ASCII碼數據是否正確呢?1種是找一個TCP/IP工具發送過去,這種麻煩了點,我推薦用fiddler監聽。
你可以快速方便的用一個web頁面輸出你的ASCII碼,在fiddler的HexView中,就可以看到原汁原味你發送的16進制數據了。另外,由于Swoole的監聽類是CLI運行,因此我也非常推薦多寫一點echo打印一下狀態,在phpstorm的SSH客戶端里可以快速的了解目前的情況,就像android-studio的Loger一樣。
echo Carbon::now() . '/Device Numbers:' . $devNum . PHP_EOL;//老司機勸你多寫點,最好packagist找個輪子或者自己寫個Logger庫
魯棒性探討,可以搞得非常復雜##
算吐個槽吧,前年用.NET做下位機數據處理魯棒性的時候真是如坐針氈啊。搞下位機通信果然還是c++最合適啊,以下問題在這里還需要后期逐步完善呢:
1.如果硬件發送的數據不是一個包發完而是分批發怎么辦?
2.看門狗是一定要寫的,對吧?
3.與硬件通信的response處理要做吧?
4.TimeOut怎么辦?
....
啊啊啊啊啊....
喜歡Android的有福了##
預告下,基于學習的目的,最近正在仿鮮城、enjoy、半糖這3個很有代表性的電商APP首頁UI(是逆向著看smali和提取res在仿喲)。鮮城的android端已經做的有模有樣了,這次是逼著自己android、ios都給仿出來,沒老司機帶就自己想辦法提高。先做android的,有興趣的朋友可以耐心等待代碼和文章。