摘要:初始化發送消息判斷用戶是否登錄如果沒有登錄拒絕連接斷開清除信息處理協議主要是方法,輪訓獲取消息。
這個列子主要討論Tcp,WebSocket和http之間的通訊。長連接和長連接通訊,長連接和短連接通訊。其他協議同理可得
Tcp: 代表硬件設備 WebSocket: 代表客戶端 http: 代表網頁
本列子是基于one框架 (https://github.com/lizhichao/one) 開發.
配置協議 監聽端口由于swoole的模型 WebSocket server 包含 http server , http server 包含 tcp server 。
所以我們配置主服務為 WebSocket server ,添加兩個http 和 tcp 監聽。配置文件如下:
return [ "server" => [ "server_type" => OneSwooleOneServer::SWOOLE_WEBSOCKET_SERVER, "port" => 8082, "action" => AppTestMixProWs::class, "mode" => SWOOLE_PROCESS, "sock_type" => SWOOLE_SOCK_TCP, "ip" => "0.0.0.0", "set" => [ "worker_num" => 5 ] ], "add_listener" => [ // http 監聽 [ "port" => 8081, "action" => AppServerAppHttpPort::class, "type" => SWOOLE_SOCK_TCP, "ip" => "0.0.0.0", "set" => [ "open_http_protocol" => true, "open_websocket_protocol" => false ] ], // tcp 監聽 [ "port" => 8083, "pack_protocol" => OneProtocolText::class, // tcp 打包,解包協議,方便在終端調試 我們使用 text 協議. 換行符 表示一個包的結束 "action" => AppTestMixProTcpPort::class, "type" => SWOOLE_SOCK_TCP, "ip" => "0.0.0.0", "set" => [ "open_http_protocol" => false, "open_websocket_protocol" => false ] ] ] ];
接下來去 AppTestMixProWs 和 AppTestMixProTcpPort 實現各種事件處理。
AppServerAppHttpPort 是框架內置的,通過路由處理http請求的,配置路由即可。
// 首頁 Router::get("/mix", [ "use" => HttpController::class . "@index", "middle" => [AppTestMixProTestMiddle::class . "@isLogin"] // 中間件 如果用戶登錄了 直接跳轉到相應的頁面 ]); Router::group([ "middle" => [AppTestMixProTestMiddle::class . "@checkSession"] // 中間件 讓用戶登錄后 才能進入聊天頁面 http websocket 都能獲取到這個 session ], function () { // websocket 頁面 Router::get("/mix/ws", HttpController::class . "@ws"); // http 頁面 Router::get("/mix/http", HttpController::class . "@http"); // http 輪訓消息接口 Router::post("/mix/http/loop", HttpController::class . "@httpLoop"); // http 發送消息接口 Router::post("/mix/http/send", HttpController::class . "@httpSend"); });
配置的都是 http 協議路由。 websocket和tpc我們直接在回調action處理。如果你的項目復雜也可以配置相應的路由。one框架的路由支持任何協議,使用方法也是統一的。
處理tcp協議其中__construct,onConnect,onClose 不是必須的。
如果你想在服務器運行開始時最一些事情就寫到 __construct里面。
onConnect 當有客戶端連接時觸發,每個客戶端觸發一次
onClose 當有客戶端連接斷開時觸發,每個客戶端觸發一次
class TcpPort extends Tcp { use Funs; private $users = []; /** * @var Ws */ protected $server; /** * @var Client */ protected $global_data; public function __construct($server, $conf) { parent::__construct($server, $conf); $this->global_data = $this->server->global_data; } // 終端連接上服務器時 public function onConnect(swoole_server $server, $fd, $reactor_id) { $name = uuid(); $this->users[$fd] = $name; $this->sendTo("all", json_encode(["v" => 1, "n" => $name])); $this->sendToTcp($fd, json_encode(["v" => 4, "n" => $this->getAllName()])); $this->global_data->bindId($fd, $name); $this->send($fd, "你的名字是:" . $name); } // 消息處理 像某個name 發送消息 public function onReceive(swoole_server $server, $fd, $reactor_id, $data) { $arr = explode(" ", $data); if (count($arr) !== 3 || $arr[0] !== "send") { $this->send($fd, "格式不正確"); return false; } $n = $arr[1]; $d = $arr[2]; $this->sendTo($n, json_encode(["v" => 3, "n" => $d])); } // 下線 通知所有其他終端,解除與fd的關系綁定。 public function onClose(swoole_server $server, $fd, $reactor_id) { echo "tcp close {$fd} "; $this->global_data->unBindFd($fd); $this->sendTo("all", json_encode(["v" => 2, "n" => $this->users[$fd]])); unset($this->users[$fd]); } }
定義了一個公共的traitFuns主要實現兩個方法,獲取所有的終端(tcp,ws,http),和向某個用戶發送消息 。在ws、http都會用到這個
在構造函數我們初始化了一個 global_data 用來保存,名稱和fd的關系。你也可以使用方式儲存。因為fd沒次連接都不同。global_data是one框架內置的。
終端連接上服務器時觸發事件 onConnect ,我們給這個終端取個名字,并把關系保存在 global_data。 通知所有終端有個新終端加入,并告訴剛加入的終端當前有哪些終端在線。
其中__construct,onHandShake,onOpen,onClose 不是必須的。
onHandShake,onOpen 是配合使用的,如果onOpen返回false服務器會拒絕連接。
在 onOpen,onMessage,onClose可以拿到當前用戶的session信息和http是相通的。
class Ws extends WsServer { use Funs; private $users = []; /** * @var Client */ public $global_data = null; public function __construct(swoole_server $server, array $conf) { parent::__construct($server, $conf); $this->global_data = new Client(); } // 初始化session public function onHandShake(swoole_http_request $request, swoole_http_response $response) { return parent::onHandShake($request, $response); } // ws 發送消息 public function onMessage(swoole_websocket_server $server, swoole_websocket_frame $frame) { $data = $frame->data; $arr = json_decode($data, true); $n = $arr["n"]; $d = $arr["d"]; $this->sendTo($n, json_encode(["v" => 3, "n" => $d])); } // 判斷用戶是否登錄 如果沒有登錄拒絕連接 public function onOpen(swoole_websocket_server $server, swoole_http_request $request) { $name = $this->session[$request->fd]->get("name"); if ($name) { $this->users[$request->fd] = $name; $this->sendTo("all", json_encode(["v" => 1, "n" => $name])); $this->global_data->bindId($request->fd, $name); return true; } else { return false; } } // ws 斷開清除信息 public function onClose(swoole_server $server, $fd, $reactor_id) { echo "ws close {$fd} "; $this->global_data->unBindFd($fd); $this->sendTo("all", json_encode(["v" => 2, "n" => $this->users[$fd]])); unset($this->users[$fd]); } }處理 http 協議
主要是 httpLoop 方法,輪訓獲取消息。因為http是短連接,發給http的信息我們是先存放在$global_data,然后直接這里讀取。防止連接間隙丟信息。
class HttpController extends Controller { use Funs; /** * @var Ws */ protected $server; /** * @var Client */ protected $global_data; public function __construct($request, $response, $server = null) { parent::__construct($request, $response, $server); $this->global_data = $this->server->global_data; } /** * 首頁 */ public function index() { $code = sha1(uuid()); $this->session()->set("code", $code); return $this->display("index", ["code" => $code]); } /** * ws頁面 */ public function ws() { $name = $this->session()->get("name"); if (!$name) { $name = uuid(); $this->session()->set("name", $name); } return $this->display("ws",["users" => $this->getAllName(),"name" => $name]); } /** * http 頁面 */ public function http() { $name = $this->session()->get("name"); if (!$name) { $name = uuid(); $this->session()->set("name", $name); } $this->global_data->set("http.{$name}", 1, time() + 60); $this->sendTo("all", json_encode(["v" => 1, "n" => $name])); return $this->display("http", ["list" => $this->getAllName(), "name" => $name]); } /** * http輪訓 */ public function httpLoop() { $name = $this->session()->get("name"); $this->global_data->set("http.{$name}", 1, time() + 60); $i = 0; do { $data = $this->global_data->getAndDel("data.{$name}"); $i++; co::sleep(0.1); } while ($data === null && $i < 300); if ($data) { foreach ($data as &$v) { $v = json_decode($v, true); } } else { $data = []; } return $this->json($data); } /** * http發送消息 */ public function httpSend() { $n = $this->request->post("n"); $d = $this->request->post("d"); if ($n && $d) { $this->sendTo($n, json_encode(["v" => 3, "n" => $d])); return "1"; } return "0"; } public function __destruct() { } public function __call($name, $arguments) { return $this->server->$name(...$arguments); } }
到此基本就完成了。你可以去看完整的代碼 : 點這里
其他的一些列子 : https://github.com/lizhichao/...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/31219.html
摘要:而要實現物物相連,一共有個階段性任務,而這個階段性任務,也伴隨著巨大的挑戰本文分享自華為云社區云駐共創以小窺大,從一盞路燈看億萬物聯網之路云駐共創以小窺大,從一盞路燈看億萬物聯網之路,作者啟明。 摘要:IoT, Internet of Things,物聯網,顧名思義,是物物相連。而要實現物...
摘要:去年月,阿里云宣布將設立阿里云廣東研發中心,招募名云計算和人工智能工程師,推動前沿技術與廣東產業融合。吳維剛表示,人工智能與云計算,兩者不是同一事物,但是相互發展。近年來,隨著互聯網和移動互聯網的蓬勃發展,大數據、云計算、人工智能、物聯網等新技術也迎來了廣闊的發展空間。去年,阿里云工業互聯網全國總部正式在廣州揭牌成立,阿里云將聯合廣東本地合作伙伴,共同打造服務全國的工業大腦。去年9月,華為與...
摘要:通過通信線路連入通信子網終端是用戶訪問網絡的界面網絡操作系統是相對于主機操作系統而言的。接收方使用同一擴頻碼進行擴解。 目錄 一、計算機網絡 1.計算機網絡技術概述 2.計算機網絡分類 3.無線網絡分類 二、無線通信和網絡仿真技術基礎 1.基本概念 2.調制 (1)、概述 (2)、常用方式 ...
摘要:一個輕量級高效率的支持聊天與物聯網的通訊框架從月初到現在已經大約已經三個月了,由于一直沒有時間與精力很好的維護這個項目,心里一直有所歉意。希望本項目對你有所幫助,我的目標暫定,一個小眾加物聯網的開源通訊項目。 篇幅較長,感謝閱讀。 萬事開頭難 在我決定做開源是因為自身工作接觸到大多數的項目都是基于開源大佬寫的框架,自覺慚愧,工作以來一直忙于業務與功能實現,多多少少做過的幾個項目也沒能抽...
閱讀 2493·2021-08-11 11:16
閱讀 2931·2019-08-30 15:55
閱讀 3335·2019-08-30 12:53
閱讀 1571·2019-08-29 13:28
閱讀 3269·2019-08-28 18:17
閱讀 940·2019-08-26 12:19
閱讀 2471·2019-08-23 18:27
閱讀 708·2019-08-23 18:17