"PHP是最好的(互聯網+物聯網)語言!",聽說發佈PHP開源產品都要慣例的喊上這麼一句。 -2016.10.17 發此文之際是OHSCEV0.1.22版本php
開啓第一篇教程前總要賣點情懷,本人本科學習建築電氣與智能化專業(即電氣工程及其自動化專業),一直是名正經的電氣工程師。其實原本和這個號稱是「Web語言」的PHP八竿子打不着,但是隨着國家所謂「互聯網+「的引導,也翻山越嶺的將WEB領域逐漸和各行各業拉到了一塊兒。從不少行業的角度看「互聯網+「很大程度就是「WEB+」,因而PHP這門最好的語言便進入了個人技術棧,我發現PHP是最具潛力的工控、物聯網&智能化語言。html
打開PHP的官網,咱們能夠看見兩行白色的歡迎語:「PHP is a popular general-purpose scripting language that is especially suited to web development.Fast, flexible and pragmatic, PHP powers everything from your blog to the most popular websites in the world.」 -意譯:PHP是一各流行且全能的腳本語言,特別合適於與互聯網相關的領域。它快速、靈活且實用,健壯的PHP能驅動小到你的博客大到著名的FACEBOOK、百度等每一個事物。linux
工控工業4.0、物聯網、行業智能化將是PHP的下一個最具潛力的領域。本着不造輪子多改進的原則我曾用款現有的PHP通訊框架(不含串口通訊功能)作過一次控制系統的實現,結果那幾天攪合的我一團糟,不少奇怪的問題和很高的失誤率,其實人家的框架是很是優秀的WEB框架多是控制領域的技術棧和傳統的WEB領域有着很大的區別,傳統的web工程師更多的工做內容和一個強大的瀏覽器或APP交互而控制工程師則不是,因而我決定從底層重寫一套代碼(同時也加上了串口通訊和共享內存輔助託管功能)。這套代碼專爲控制環境量身定製,是專業針對工控工業4.0、物聯網、行業智能化場景(固然兼備了作WEB的能力,畢竟「」互聯網+「」嘛)。其實母程序已幾經實布和商布,咱們將其核心部分剝離出來繼而作了開源化改動併合並了OpenIAC計劃成爲了爲控制場景量身定製的高可靠性PHP通訊&控制框架-OHSCE。它簡單高效而且特別親切於工業自動化工程師、硬件工程師、物聯網工程師、追求效率的PHP工程師的寫法風格,也能讓傳統的PHP-WEB工程師輕鬆上手。git
言歸正傳咱們以搭建一個簡單的串口服務器做爲第一教程的內容,一個簡單的串口服務器包含了上行網絡(以太網)和現場總線(這裏是RS485通訊)。github
以太網作上行網絡是大勢所趨,RS485是目前使用最廣泛普遍也是最具性價比的現場通訊手段,固然不少其它通訊手段均可以和RS232/485轉接,故咱們以它作例。web
#用UDP仍是TCP?windows
UDP是一個很是好的選擇,它無連接、高效而且節約資源,可是缺點是會有丟包的可能性,不過您能夠經過主從應答來保證您的數據的可靠性,並且您能夠靈活的掌握是否應答,甚至這各特性均可以邏輯中的一部分。不過對於串口服務器這個場景來講TCP是更合適的選擇,由於作一個串口的需求很簡單,可靠鏈接讀寫數據並轉發到串口上,串口寫讀數據並回轉回來。咱們肯定使用TCP數組
示例所使用的機器的COM7是將使用的串口。瀏覽器
#欲善其事必利其器服務器
下載最新版本的OHSCE:
您能夠到OHSCE的官網(http://www.ohsce.org)或GITHUB(https://github.com/OpenIBC/Ohsce)下載到最新的OHSCE。PS.記得支持我一下哦
安裝PHP5.4+ 並配置PHP.INI至可用狀態。
配置OHSCE的配置文件 位於.../config/
開啓Curl擴展、Shmop擴展、Sockets擴展
建立OhsceComserver.php文件
加載OHSCE
<?php ini_set('memory_limit',"64M"); //重置php可使用的內存大小爲64M set_time_limit(0); //重置運行時長爲無限制 ob_implicit_flush(1); include('loadohsce.php'); //載入Ohsce加載文件
#開始構造串口服務器的身軀
首先咱們打開咱們須要轉發的串口
<?php //...... $comid="COM7"; //windows下是comx linux下是/dev/ttyX Ohsce_eng_serial_creat($hscecom,$comid); //建立一個COM7 9600,n,8,1的待調用串口資源 Ohsce_eng_serial_open($hscecom); //調用資源並佔用該串口
PS:Ohsce_eng_serial_creat函數默認爲您填充了您所省略的全部相關參數,固然您能夠手動指定他們以建立各類串口資源。
Ohsce_eng_serial_creat(&$OHSCESerial,$com,$flags="1",$mode=0,$baud=9600,$parity='n',$data=8,$stop=1,$fc='none',$xon='off',$to='off',$octs='off',$odsr='off',$idsr='off',$dtr='on',$rts='on')
在建立TCP服務器以前咱們須要先構造它的回調函數。 所謂回調函數就是當有新的TCP客戶端到達、客戶端發送新的消息到達是會調用的函數。
<?php //................... function comserveraccept(&$socket,$ip,$port,$zv){ global $hscecom; //調用$hscecom串口資源 $ohsce_cs_data=Ohsce_socketread($socket,1024); //讀取1024字節數據 if(($ohsce_cs_data!=null)or($ohsce_cs_data[0]!=false)){ Ohsce_eng_serial_write($hscecom,$ohsce_cs_data[1],false);//寫入串口 Ohsce_eng_serial_read($hscecom,$data,null,true); //讀取返回數據 Ohsce_socketwrite($socket,$data); //迴轉所讀取的數據 } return true; } function comservera(&$socket,$buf,$len,$zv){ global $hscecom; Ohsce_eng_serial_write($hscecom,$buf,false); Ohsce_eng_serial_read($hscecom,$data,null,true); Ohsce_socketwrite($socket,$data); return true; } function comserveralways(&$oibc_clients_zv){ global $hscecom; Ohsce_eng_serial_read($hscecom,$data,null,true); if((!is_null($data))and(strlen($data)>0)){ foreach($oibc_clients_zv['clients'] as $okey => $osclient){ if($okey=="0"){ continue; } Ohsce_socketwrite($osclient,$data); } } return true; }
其中comserveralways函數是每圈循環都會執行一次的函數,也就是常駐函數。在咱們的串口服務器程序中,他會將最新收到的串口數據轉發廣播出去。
comservera(&$socket,$buf,$len,$zv)和comserveraccept(&$socket,$ip,$port,$zv)函數會被固定傳入這些變量。其中$socket是本次活動的socket資源的指針。$buf是收到的數據。$len是數據長度。$ip是新到客戶端的ip地址。$port是其端口。$zv是固定結構體,其結構以下:$oibc_clients_zv=array("clients"=>&$oibc_clients,"ip"=>&$oibc_clients_id_ip,"id"=>&$oibc_clients_id)
其中$oibc_clients數組爲當前全部socket資源,key值爲0者爲服務監聽者。$ip數組爲ip對照表。$id數組爲id備份表。固然若是有須要您也能夠print_r之一探究竟。
小提示:print_r函數是您的好幫手,不少時候文檔很難面面俱到QQ羣我也很難隨時關注,這時候print_r可能比度娘還親切。
#賦予它生命的力量
好了,回調函數和常駐函數都造好了,下面咱們改讓它擁有跑起來的能力了。首先先建立一個可複用的TCP服務端資源,第二步傳入讓它跑起來,就那麼簡單。
<?php Ohsce_eng_socket_server($ohsceserver,'tcp','7626','127.0.0.1',array('callback'=>'comservera','accept'=>'comserveraccept','fap'=>'comserveralways'),'comserveraccept'); //建立一個能夠複用的SOCKETSERVER資源$ohsceserver,協議爲TCP,監聽端口爲7626,綁定IP127.0.0.1,回調函數爲comservera,首次回調函數爲comserveraccept,常駐函數爲comserveralways.最後一個comserveraccept是爲了兼容OHSCEV0.1.22之前的版本。 Ohsce_eng_socket_server_runtcp($ohsceserver); //運行它
固然更詳細的能夠參考手冊文檔: Ohsce_eng_socket_server Ohsce_eng_socket_server_runtcp
PS:一個彩蛋,當你的實際生產中最好不要使用7626端口,由於它太著名了,曾經咱們漫遊在整個互聯網上尋找開了7626端口的小夥伴。簡單的來講,容易招黑,並且招來的都是老黑:)
#一個我的認爲的好習慣
不管您的程序多麼的完美,最後記得阻截並跳轉去拋出錯誤。這樣當您的程序擴展和改動其它部分時至少能保證某一部分運行的不錯。
<?php //..程序頭...... $errmsg='Unknow'; //............. //..程序身軀.... //............. goto terror; //前往並拋出錯誤 //............. terror: //拋出錯誤的錨點 exit($errmsg);
關於goto,能夠理解爲JMP指令,熟悉的身影可是用法略有不一樣。在PHP中GOTO是不能夠從一個函數跳到另外一個函數的,同時也是不能夠從一個文件跳到另外一個文件的。其實,這個限制帶來了您程序可讀性的提高和性能&一致性的平衡。
PS.其實在不少高級語言中別說兇殘的SETJMP了,連GOTO/JMP都被取締了。緣由是在號幾十年前覺得叫「Edsger Wybe Dijkstra」的先生提出了GOTO有害論,因而被不少人奉爲聖旨而流傳下來甚至在很多語言中乾脆就被砍掉了(如JAVA)。這的確,大大的下降了程序設計對人員要求的門檻,但隨着發展,尤爲咱們進入了泛(互)物(聯)聯(網)網(+)時代,GOTO的親切與做用顯得愈發的重要。不過進入21世紀不久 Dijkstra先生就去世了,英明的PHP設計團隊在2009年將GOTO關鍵字從新引入了這門「世界上最好的語言」,因此從5.3開始咱們又可使用高效、簡潔、具有自底向上一致性的GOTO關鍵字了。
#牛刀小試
至此,一個簡單的串口服務器原型工程完成了。其實它不只僅是一個教程案例,更是一個很是實用的功能,我將它包裝了一下,這個原型便以Alpha的身份加入了V0.1.22_BETA開源版的Engine中。在後續的版本中它將跟隨着OHSCE的版本更新變得愈來愈健壯。
<?php //....................................... comserver: $oibc_cnp_csa=getopt('r:m:p:c:'); Ohsce_eng_serial_creat($hscecom,trim($oibc_cnp_csa['c'])); Ohsce_eng_serial_open($hscecom); function comserveraccept(&$socket,$ip,$port,$zv){ global $hscecom; $ohsce_cs_data=Ohsce_socketread($socket,1024); if(($ohsce_cs_data!=null)or($ohsce_cs_data[0]!=false)){ Ohsce_eng_serial_write($hscecom,$ohsce_cs_data[1],false); Ohsce_eng_serial_read($hscecom,$data,null,true); Ohsce_socketwrite($socket,$data); } return true; } function comservera(&$socket,$buf,$len,$zv){ global $hscecom; Ohsce_eng_serial_write($hscecom,$buf,false); Ohsce_eng_serial_read($hscecom,$data,null,true); Ohsce_socketwrite($socket,$data); return true; } function comserveralways(&$oibc_clients_zv){ global $hscecom; Ohsce_eng_serial_read($hscecom,$data,null,true); if((!is_null($data))and(strlen($data)>0)){ foreach($oibc_clients_zv['clients'] as $okey => $osclient){ if($okey=="0"){ continue; } Ohsce_socketwrite($osclient,$data); } } return true; } Ohsce_eng_socket_server($ohsceserver,'tcp',intval(trim($oibc_cnp_csa['p'])),OHSCE_MYIP_SYSTEM,array('callback'=>'comservera','accept'=>'comserveraccept','fap'=>'comserveralways'),'comserveraccept'); Ohsce_eng_socket_server_runtcp($ohsceserver); //開始運行 goto terror; //.......................................
好了下面咱們啓動它並使用TCP鏈接串口服務器在COM7串口上使用MODBUS-RTU協議讀取一臺壓力變送器的數據。
tcpComClient.php:
<?php ini_set('memory_limit',"88M");//重置php可使用的內存大小爲64M set_time_limit(0); ob_implicit_flush(1); error_reporting(0); include('loadohsce.php'); Ohsce_eng_socket_client($ohsceclient,'tcp',7628,'127.0.0.1'); //建立一個TCP客戶端資源並鏈接27.0.0.1:7626 Ohsce_socketsend($ohsceclient['socket'],"\x01\x03\x00\x01\x00\x04\x15\xc9"); //發送數據 //Ohsce_socketsend($ohsceclient['socket'],array('in'=>"01030001000415c9",'bin'=>true)); echo Ohsce_socketread($ohsceclient['socket'],1024)[1]; //收取回複數據 sleep(30);
運行效果:
PHP是一個健壯的全能腳本語言,特別適合於網絡有關的場景。工業控制、物聯網、行業智能化方向,OHSCE是您強大的戰艦。
OHSCE官方網站: HTTP://WWW.OHSCE.ORG
技術&交流:Q羣-374756165 (隨風星海@做者)
手冊地址:http://www.ohsce.com/index.php/book/ohscelib/
GITHUB:https://github.com/OpenIBC/Ohsce
GIT@OSC:https://git.oschina.net/SFXH/Ohsce
捐助&支持:http://www.ohsce.com/index.php/company/