(寫於OHSCEV0.1.23)
面對以太網我們需要使用TCP/UDP進行通信,TCP/UDP在世界互聯網範圍內被廣泛使用,同時它也被廣泛應用於物聯網、工業網等控制通信網上。不過區別於互聯網上的極致追求高併發高效率普通應用,更偏重的是與瀏覽器/應用客戶端交互。我們的應用場景是與控制設備交互,更注重準確性、可靠性、穩定性。也正是因此目前純粹的基於TCP/UDP的NCS控制系統在大型系統基本是不可行的,但是事情不是一成不變的,總要動態的去看問題。隨着網絡技術的發展越來越成熟,我們越來越多的要去接觸它,在控制領域對它的使用和在普通應用中對它的使用是有很多不同的,OHSCE爲您平衡了它們。另外個人認爲複合型的控制系統是相對科學的。
一、OHSCE中的TCP/UDP函數族。
主要分爲封裝函數和基礎函數,絕大多數的需求使用封裝函數即可完成,但是OHSCE也提供給您了操作更接近底層的基礎函數庫。
封裝函數Ohsce_eng_socket_X。
首先在建立一個SERVER/CLIENT之前需要先構建一個鏈接預備資源,其實此資源在OHSCE中就是一個數組結構,存儲了這個資源在調用和運行中需要的各個數據。構建一個鏈接預備資源非常簡單,只需要一個函數就可以解決。
CLIENT: Ohsce_eng_socket_client
SERVER: Ohsce_eng_socket_server
DO: Ohsce_eng_socket_send Ohsce_eng_socket_recv Ohsce_eng_socket_server_runtcp Ohsce_eng_socket_server_runudp Ohsce_eng_socket_server_close
二、我們先構建一個CLIENT:
TCP:
Ohsce_eng_socket_client($ohsceclient,'tcp',7628,'127.0.0.1'); //創建一個TCP客戶端資源並連接127.0.0.1:7626
UDP:
Ohsce_eng_socket_client($ohsceclient,'udp',7628,'127.0.0.1'); //創建一個UDP客戶端資源並綁定127.0.0.1:7628
這樣一個變量名爲$ohsceclient的鏈接資源就創建完成了,是不是很簡單,實際上Ohsce_eng_socket_client函數還可以很強大,它有很多輸入量都被OHSCE自動爲您填充了。Ohsce_eng_socket_client(&$OhsceClient,$protocol,$port,$ip=null,$AF='ipv4',$sync=true,$mode='defalut') 函數支持您創建不同協議的客戶端模式鏈接資源,支持IPV4和IPV6(默認爲IPV4),支持同步和異步,和多種預設定模式(默認爲default)
三、再構建相應的SERVER
其實TCP是有鏈接的而UDP是無鏈接的,而所謂UDPSERVER資源只是在告訴OHSCE應該以SERVER姿態去運行這個資源。
Ohsce_eng_socket_server函數能夠幫助你輕鬆的創建一個SERVER預備資源。但是在創建這個資源之前我們還需要兩件件事情要做。
第一件是爲SERVER資源預備回調函數。其中TCP需要兩個回調函數,UDP需要一個回調函數。
TCP回調函數分別爲新客戶端到達函數(callbackaccept)和舊客戶端回調函數(callback),新客戶端到達回調函數其實就是TCP握手後第一個信息。因爲這個信息很多時候是一個硬件登陸信息,如果您的設備沒有登陸動作那您可以不準備此函數。舊客戶端回調函數是每次有數據到達都會調用的一個函數。
舉個栗子:
function example(&$socket,$buf,$len,$zv){ //收到數據時的回調函數
echo $buf;
Ohsce_socketwrite($socket,'hi '.$buf);
return true;
}
function exampleaccept(&$socket,$ip,$port,$zv){ //新客戶端到訪時的回調函數
Ohsce_socketwrite($socket,'Welcome'.$ip.':'.$port);
return true;
}
其中example函數會被傳入本次連接的socket資源的指針,$buf爲數據內容,$len爲數據長度,$zv爲OHSCE固定結構體(數組形式)。
<?php
$zv=array("clients"=>&$oibc_clients,"ip"=>&$oibc_clients_id_ip,"id"=>&$oibc_clients_id);
這個數組會由OHSCE自動生成並傳遞給您。其中clients是客戶端列表(包含一個佔位符,這個您不用管),ip是客戶端ip表,id是客戶端表備份便於您回滾。您可以操作它管理各數據,包含手動進行心跳操作(如果您的需求需要)。
另一個函數exampleaccept(&$socket,$ip,$port,$zv)是在新客戶端到訪時被調用的。
第二件事是構建常駐函數
常駐函數是每次循環都會被執行的函數,如果您不需要完全可以直接寫成。
<?php
function fap(&$zv){
return true;
}
傳入的參數只有結構體數組$zv.此函數很多情況下是用於手動發送心跳的(如果需要)。
好了倆事都辦完了我們現在可以構建SERVER了。
<?php
Ohsce_eng_socket_server($ohsceserver,'tcp',7626,'127.0.0.1',array('callback'=>'example','accept'=>'exampleaccept','fap'=>'fap'),'example');
其中$ohsceserver就是我們構建好的server。後面依次是tcp協議,7627端口,回調函數組(只需要傳入函數名即可),最後一個回調函數名是0.1.X兼容寫法。其實OHSCE的SERVER遠比演示強大,可以參考文檔。
四、讓SERVER運轉起來並使用CLIENT去連接
在OHSCE中運轉一個SERVER是非常容易的事情,對於基礎的需求只需要一個函數你的SERVER就被激活並開始運轉了。
Ohsce_eng_socket_server_runtcp($ohsceserver); //開始運行
這時候,一個服務端口是7627佔用IP是127.0.0.1,回調函數是example()歡迎函數exampleaccept(),並且每各循環都會運行一個fap()常駐函數的TCPSERVER就啓動啦。
現在我們可以CLIENT文件添加讀寫操作。
Ohsce_socketsend($ohsceclient['socket'],'hello'); //發送數據
echo Ohsce_socketread($ohsceclient['socket'],1024)[1]; //收取回複數據
運行CLIENT文件,其實客戶端資源在創建時默認就進行了連接(至少目前版本是這樣設計的),所以直接就可以進行讀寫操作了。
六、有關UDP
UDP和TCP的區別是UDP是無連接的通信協議而TCP是有鏈接的通信協議,所以理論上TCP比UDP更可靠一些。但是在本機或可靠的設備內網,其可靠性方面的差異並不大但畢竟UDP風險還是略高一些,但是對於非關鍵位置的查詢型設備設計上下位機通信是還是可以考慮此協議。所以還是能見到UDP控制設備的,雖然其很少見,筆者就遇到過,我們舉一個UDP的使用例子。
UDPSERVER
ini_set('memory_limit',"88M");//重置php可以使用的內存大小爲88M
set_time_limit(0);
ob_implicit_flush(1);
include('loadohsce.php');
$trya='ohsce_server_Example ';
function example(&$socket,$buf,$from,$port,$zv){ //收到數據時的回調函數
global $trya;
echo $buf;
Ohsce_socketsend($socket,$trya.'hi '.$buf,0,0,$from,$port);
return true;
}
function fap(&$zv){
return true;
}
Ohsce_eng_socket_server($ohsceserver,'udp',7626,'127.0.0.1',array('callback'=>'example','fap'=>'fap'));//創建一個UDP服務端資源 綁定127.0.0.1:7626 並傳入回調函數
@Ohsce_eng_socket_server_runudp($ohsceserver); //開始運行
其實UDP沒有SERVER概念,所謂SERVER只是我們的邏輯SERVER罷了。
UDPCLIENT
ini_set('memory_limit',"88M");//重置php可以使用的內存大小爲64M
set_time_limit(0);
ob_implicit_flush(1);
include('loadohsce.php');
Ohsce_eng_socket_client($ohsceclient,'udp',7628); //創建一個UDP客戶端資源並綁定7628
Ohsce_socketsend($ohsceclient['socket'],'hello',0,0,'127.0.0.1',7626);
Ohsce_socketrecvfrom($ohsceclient['socket'],$buf,0,0,$from,$port); //收取回複數據
echo $buf.'|'.$from.':'.$port;
sleep(30);
同樣,這只不過是邏輯客戶端罷了。
顯而易見,UDP帶來了高效、簡單、迅捷的優點,但是別忘了它的硬傷它並不確保數據可靠到達和到達順序。不過一般情況下,UDP設備均有應答機制。
七、科學的拆分你的邏輯到回調函數和常駐函數中去。