官網:https://www.workerman.net/
手冊地址:https://www.workerman.net/doc
追加內容:
請在開發前多讀讀 開發必讀http://doc.workerman.net/development/before-development.html
追加內容結束
第一次使用workerman,目標要求實現客戶端與服務器1對1的通信。
第一次嘗試:
前端js
//文檔地址
//http://doc.workerman.net/getting-started/simple-example.html
// 假設服務端ip為127.0.0.1
ws = new WebSocket("ws://127.0.0.1:2000");
ws.onopen = function() {
alert("連接成功");
ws.send('tom');
alert("給服務端發送一個字符串:tom");
};
ws.onmessage = function(e) {
alert("收到服務端的消息:" + e.data);
};
后端 php
//文檔地址
//http://doc.workerman.net/getting-started/simple-example.html
<?php
use Workerman\Worker;
require_once __DIR__ . '/Workerman/Autoloader.php';
// 注意:這里與上個例子不同,使用的是websocket協議
$ws_worker = new Worker("websocket://0.0.0.0:2000");
// 啟動4個進程對外提供服務
$ws_worker->count = 4;
// 當收到客戶端發來的數據后返回hello $data給客戶端
$ws_worker->onMessage = function($connection, $data)
{
// 向客戶端發送hello $data
$connection->send('hello ' . $data);
};
// 運行worker
Worker::runAll();
命令行: 代碼部署完畢之后需要在命令行中啟動
// 文檔地址 // http://doc.workerman.net/install/start-and-stop.html // 以下運行方式任選一種 // 線上環境需要以守護進程方式啟動 並且要加心跳[如果不會請百度] //以debug(調試)方式啟動 php start.php start //以daemon(守護進程)方式啟動 php start.php start -d
總結:
1.在測試中發現本方法如果只開啟一個進程只能夠連接一個客戶端,超出一個客戶端的連接會出現連接失敗,需要等待上一個連接斷開之后才能夠進行下一個連接[四個進程只能連接四個客戶端],但是文檔說單個進程最多可以支持5w連接數,手冊查找原因【本答案未必准確,百度未找到類似答案 僅作參考】:
追加:
1.不能多人連接是因為php代碼出現了報錯,如果不能多人連接請解決所有錯誤
2.不要使用 sleep exit die 函數 導致進程停止或結束
// 文檔地址
// http://doc.workerman.net/development/before-development.html
//三、區分主進程和子進程
//有必要注意下代碼是運行在主進程還是子進程,一般來說在Worker::runAll();調用前運行的代碼都是在主進程運行的,onXXX回調運行的代碼都屬於子進程。注意寫在Worker::runAll();后面的代碼永遠不會被執行。
//例如下面的代碼
require_once __DIR__ . '/Workerman/Autoloader.php';
use Workerman\Worker;
// 運行在主進程
$tcp_worker = new Worker("tcp://0.0.0.0:2347");
// 賦值過程運行在主進程
$tcp_worker->onMessage = function($connection, $data)
{
// 這部分運行在子進程
$connection->send('hello ' . $data);
};
Worker::runAll();
//注意: 不要在主進程中初始化數據庫、memcache、redis等連接資源,因為主進程初始化的連接可能會被子進程自動繼承(尤其是使用單例的時候),所有進程都持有同一個連接,服務端通過這個連接返回的數據在多個進程上都可讀,會導致數據錯亂。同樣的,如果任何一個進程關閉連接(例如daemon模式運行時主進程會退出導致連接關閉),都導致所有子進程的連接都被一起關閉,並發生不可預知的錯誤,例如mysql gone away 錯誤。
//推薦在onWorkerStart里面初始化連接資源。
2.當開啟多進程的時候,多個客戶端進行連接會導致用戶發送給服務器的消息會被服務器發送給所有用戶
第二次嘗試:
第一次嘗試由於不支持多人連接,所以百度及文檔查找如何進行多人連接,如果進行多人連接,那么就需要使用uid進行標示用戶,來給不同的用戶發送消息,實現一對一的消息
php
<?php
use Workerman\Worker;
require_once __DIR__ . '/Workerman/Autoloader.php';
//
$ws_worker = new Worker('websocket://127.0.0.1:2000');
// // 新增加一個屬性,用來保存uid到connection的映射(uid是用戶id或者客戶端唯一標識)
$worker->uidConnections = array();
// 手冊說只能一個
$ws_worker->count = 1;
// 當收到客戶端發來的數據后返回hello $data給客戶端
$ws_worker->onMessage = function ($connection, $data) {
global $ws_worker;
// 客戶端的第一次消息當作獲取uid
// 判斷當前客戶端是否已經驗證,即是否設置了uid
// 這里只是簡單的把 $connection->id 當作他的uid 因為 connection->id 是唯一的
if (!isset($connection->uid)) {
$connection->uid = $connection->id;
$ws_worker->uidConnections[$connection->uid] = $connection;
return $connection->send($connection->uid);
}
//獲取uid
list($uid, $message) = explode(':', $data);
//判斷id是否存在 然后發送消息
if (isset($ws_worker->uidConnections[$uid])) {
$connection = $ws_worker->uidConnections[$uid];
$connection->send("自定義消息內容");
}
};
// 運行worker
Worker::runAll();
js
ws = new WebSocket("ws://127.0.0.1:2000");
var uid = "";
ws.onmessage = function (e) {
//設置uid
if(uid == ""){
uid = e.data;
return ;
}
//實現邏輯代碼區域
//....
}
總結:
1.實現了多用戶連接[與進程數量無關]
2.顯示單個用戶與服務器的一對一的消息
