天天看點

workerman+websocket

我的需求是:

某裝置通過8093端口向伺服器推送事件資訊;

伺服器通過8093端口接收事件提取有用的資訊再通過8090端口向web端推送資訊;

web端通過8090端口接受資訊幫完成響應的動作;

我遇到的難題:

需要監聽8090端口和8093端口,但是這是兩個不同的程序,變量資料不共享;

向8090端口推送消息可以主動推送,不需要回調;

解決方案:

Workerman是一款純PHP開發的開源高性能的PHP socket 服務架構。

http://doc.workerman.net/

用的是workerman的Channel分布式通訊元件解決方案

代碼:

<?php
use Workerman\Worker;
require_once __DIR__ . '/Workerman/Autoloader.php';
require_once __DIR__ . '/Channel/src/Server.php';
require_once __DIR__ . '/Channel/src/Client.php';

// 初始化一個Channel服務端
$channel_server = new Channel\Server('0.0.0.0', 2206);

// websocket服務端
$worker = new Worker('websocket://0.0.0.0:8090');
$worker->count=1;
$worker->name = 'pusher';
$worker->onWorkerStart = function($worker)
{
    // Channel用戶端連接配接到Channel服務端
    Channel\Client::connect('0.0.0.0', 2206);
    // 訂閱廣播事件
    $event_name = 'sendWeb';
    Channel\Client::on($event_name, function($event_data)use($worker){
        $message = $event_data['content'];
		// echo $message;
		//向訂閱了sendWeb事件的用戶端推送資訊
        foreach($worker->connections as $connection)
        {
            $connection->send(json_encode($message));
        }
    });
};

$worker->onConnect = function($connection)use($worker)
{
    $msg = "workerID:{$worker->id} connectionID:{$connection->id} connected\n";
	echo $msg;
	$info = array("workerID"=>$worker->id,
				  "connectionID"=>$connection->id);
	$connection->send(json_encode($info));
};

//監聽來自OM20的事件,并把監聽到的資料通過channel服務端推送給訂閱了事件的程序
$http_worker = new Worker('tcp://0.0.0.0:8093');
$http_worker->name = 'publisher';
//程序啟動時就連上channel服務端
$http_worker->onWorkerStart = function()
{
    Channel\Client::connect('0.0.0.0', 2206);
};
$http_worker->onMessage = function($connection, $data)
{
	$connection->send('ok');
	if(empty($data))
	{
		echo "data is null ";
		return;
	}
	// echo "8093....................................................\n";
	//通過channel服務端推送給訂閱了sendWeb事件的程序
	$event_name = 'sendWeb';
	Channel\Client::publish($event_name, array(
	   'content'          => $info
	));
	// echo $data;
};
Worker::runAll();
           

對代碼的了解:

1.要建立一個channel端(2206端口),我的了解是這個channel就像一個中轉站,程序間的變量共享問題就是通過這個channel解決的。

2.2206向8090推送事件資訊;但是這個推送不是誰都要推送,隻會向訂閱了用戶端推送資訊,是以8090要向2206訂閱一個事件,我是命名為sendWeb了。

3.從8093收到事件資訊就向2206推送;這個推送是向某個事件(sendWeb)進行推送。

前端代碼為:

<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title></title>
</head>
<body>
  <h3>WebSocket協定的用戶端程式</h3>
  <button id="btConnect">連接配接到WS伺服器</button>
  <button id="btSendAndReceive">向WS伺服器發消息并接收消息</button>
  <button id="btClose">斷開與WS伺服器的連接配接</button>
  <div id="val"></div>
  <script>
    var wsClient = null; //WS用戶端對象
    wsClient = new WebSocket('ws://10.63.15.169:8090');
	
    wsClient.onopen = function(){
		console.log('成功連接配接伺服器')
    }
 
	wsClient.onmessage = function(res){
		let ret = JSON.parse(res.data);
		console.log('data.data為:'+ res.data)
	}
	
	wsClient.onerror = function(){
		console.log('通信發生錯誤')
	}
	
    btClose.onclick = function(){
      //斷開到WS伺服器的連接配接
      wsClient.close();  //向伺服器發消息,主動斷開連接配接
      wsClient.onclose = function(){
        //經過用戶端和伺服器的四次揮手後,二者的連接配接斷開了
        console.log('到伺服器的連接配接已經斷開')
      }
    }
  </script>
</body>
</html>
           

所有代碼本人親測有效

繼續閱讀