訂閱發布主要用于廣播系統,例如聊天系統中的群聊,消息推送,同步操作等等;這里以同步操作為例子作為講解

圖片來源于https://www.cnblogs.com/JasonLeemz/p/5116814.html
##### 大概流程如下:
- pc端游覽器與websocket建立長連接
- websocket訂閱redis (subscribe channel),一旦channel有數據,websocket主動推送數據給pc端游覽器
- 手機設備修改數據,并執行發布 (publish channel message)
- websocket獲取到channel的message,主動推送給pc游覽器
##### 注意點:
- redis的訂閱發布使用php內置的socket,默認超時時間為60秒,需要設置ini_set('default_socket_timeout', -1);
- php的redis擴展為阻塞IO,當websocket訂閱redis,整個進程會阻塞,導致服務端的websocket不能處理其他事件,從而無法記錄長連接fd,解決方法用異步redis
##### 下面是一個簡單的基于swoole異步redis實現的websocket服務端
```php
class WebsocketServer
{
public $fdMaps = [];
/** @var \Swoole\WebSocket\Server */
public $ws;
public function __construct()
{
$this->ws = new Swoole\WebSocket\Server('0.0.0.0', 9503);
$this->ws->on('open', [$this, 'open']);
$this->ws->on('close', [$this, 'close']);
$this->ws->on('workerStart', [$this, 'workerStart']);
$this->ws->on('message', [$this, 'message']);
$this->ws->set([
'worker_num' => 1,
'daemonize' => 0,
]);
$this->ws->start();
}
public function message($server, $frame)
{
$server->push($frame->fd, "hello");
}
public function workerStart(\Swoole\WebSocket\Server $server, $workerID)
{
$client = new \Swoole\Redis();
$client->on('message', function ($client, $result) use ($server) {
if ($result[0] == 'message') {
foreach ($server->connections as $fd) {
$server->push($fd, $result[2]);
}
}
});
$client->connect('127.0.0.1', 6379, function ($client, $result) {
$client->subscribe('channel');
});
}
public function open($server, $request)
{
echo "fd $request->fd connect \n";
$this->fdMaps[$request->fd] = $request->fd;
}
public function close($server, $fd)
{
if (isset($this->fdMaps[$fd])) {
unset($this->fdMaps[$fd]);
echo "fd $fd close \n";
} else {
echo "error\n";
}
}
}
new WebsocketServer();
```
html代碼:
```html
<html>
<body>
<h1>Redis publish/subscribe</h1>
<div id="show-list"></div>
</body>
</html>
<script type="text/javascript" src="/chat/js/jquery.min.js"></script>
<script>
$(function () {
var ws = new WebSocket('ws://127.0.0.1:9503');
ws.onopen = function () {
console.log('connect success');
};
// 接受消息
ws.onmessage = function (evt) {
console.log(evt.data);
var html = '<h3>' + evt.data + '</h3>';
$('#show-list').append(html);
};
ws.onclose = function () {
console.log('connect close');
};
});
</script>
```
調試:
```bash
127.0.0.1:6379> publish channel hello
(integer) 1
# 響應的pc游覽器會顯示hello
```
- php
- 編譯安裝
- 基本概念
- 垃圾回收機制
- 生命周期
- zval底層實現
- c擴展開發
- gdb調試工具
- 自定義擴展簡單demo
- 鉤子函數
- 讀取php.ini配置
- 數組
- 函數
- 類
- yaf擴展底層源碼
- swoole擴展底層源碼
- memoryGlobal內存池
- swoole協程使用記錄
- 單點登錄sso原理
- compser使用
- session實現機制
- c & linux
- gcc
- 指針
- 結構體,聯合和位字段
- 宏定義井號說明
- printf家族函數和可變參數
- 共享函數
- 靜態庫和動態庫
- makefile自動化構建
- 信號一
- 信號二
- inotify監控文件事件
- socket編程
- 簡介
- UNIX DOMAIN
- Internet DOMAIN
- TCP/IP
- 文件IO多路復用
- 內存管理
- 進程組,會話和控制終端
- daemon守護進程
- 多進程
- 多線程
- 常用進制轉換
- go
- 入門知識
- 字節和整數裝換
- python
- redis
- 應用場景
- 消息隊列
- 熱點數據
- 掃碼登錄
- 訂閱發布
- 次數限制
- 搶購超賣
- 持久化機制
- mysql
- 工作流程
- MyISAM和InnoDB區別
- 用戶和權限管理
- 執行計劃
- sql優化
- 事務和鎖
- 慢查詢日志
- case...when...then...end用法
- sql
- 參考
- linux
- 內核參數優化
- 防火墻設置
- docker
- docker入門知識
- 算法
- 多維數組合
- DFA算法
- 紅包金額分配