Server.php
5.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
<?php
namespace app\socketio\controller;
use Workerman\Worker;
use Workerman\Timer;
use PHPSocketIO\SocketIO;
use Workerman\Protocols\Http\Request;
use Workerman\Connection\TcpConnection;
class Server
{
// 全局数组保存uid在线数据
private $uidConnectionMap = array();
// 记录最后一次广播的在线用户数
private $last_online_count = 0;
// 记录最后一次广播的在线页面数
private $last_online_page_count = 0;
public function index(){
header("Access-Control-Allow-Origin: *");
// PHPSocketIO服务
$context = array(
'ssl' => array(
'local_cert' => '/usr/local/nginx/cert/chengyigou.cn/chengyigou.cn.crt',
'local_pk' => '/usr/local/nginx/cert/chengyigou.cn/chengyigou.cn.key',
'verify_peer' => false,
)
);
$sender_io = new SocketIO(2120,$context);
// 客户端发起连接事件时,设置连接socket的各种事件回调
$sender_io->on('connection', function($socket){
// 当客户端发来登录事件时触发
$socket->on('login', function ($uid)use($socket){
// global $uidConnectionMap, $last_online_count, $last_online_page_count;
// 已经登录过了
if(isset($socket->uid)){
return;
}
// 更新对应uid的在线数据
$uid = (string)$uid;
if(!isset($this->uidConnectionMap[$uid]))
{
$this->uidConnectionMap[$uid] = 0;
}
// 这个uid有++$uidConnectionMap[$uid]个socket连接
++$this->uidConnectionMap[$uid];
// 将这个连接加入到uid分组,方便针对uid推送数据
$socket->join($uid);
$socket->uid = $uid;
// 更新这个socket对应页面的在线数据
$socket->emit('update_online_count', "当前<b>{$this->last_online_count}</b>人在线,共打开<b>{$this->last_online_page_count}</b>个页面");
});
// 当客户端断开连接是触发(一般是关闭网页或者跳转刷新导致)
$socket->on('disconnect', function () use($socket) {
if(!isset($socket->uid))
{
return;
}
// global $uidConnectionMap, $sender_io;
// 将uid的在线socket数减一
if(--$this->uidConnectionMap[$socket->uid] <= 0)
{
unset($this->uidConnectionMap[$socket->uid]);
}
});
});
// 当$sender_io启动后监听一个http端口,通过这个端口可以给任意uid或者所有uid推送数据
$sender_io->on('workerStart', function() use ($sender_io) {
// 监听一个http端口
$context = array(
'ssl' => array(
'local_cert' => '/usr/local/nginx/cert/chengyigou.cn/chengyigou.cn.crt',
'local_pk' => '/usr/local/nginx/cert/chengyigou.cn/chengyigou.cn.key',
'verify_peer' => false,
)
);
$inner_http_worker = new Worker('https://0.0.0.0:2121',$context);
// 当http客户端发来数据时触发
$inner_http_worker->onMessage = function(TcpConnection $http_connection, Request $request) use ($sender_io) {
// global $uidConnectionMap;
$post = $request->post();
$post = $post ? $post : $request->get();
// 推送数据的url格式 type=publish&to=uid&content=xxxx
switch(@$post['type']){
case 'publish':
// global $sender_io;
$to = @$post['to'];
$post['content'] = htmlspecialchars(@$post['content']);
// 有指定uid则向uid所在socket组发送数据
if($to){
$sender_io->to($to)->emit('new_msg', $post['content']);
// 否则向所有uid推送数据
}else{
$sender_io->emit('new_msg', @$post['content']);
}
// http接口返回,如果用户离线socket返回fail
if($to && !isset($this->uidConnectionMap[$to])){
return $http_connection->send('offline');
}else{
return $http_connection->send('ok');
}
}
return $http_connection->send('fail');
};
// 执行监听
$inner_http_worker->listen();
// 一个定时器,定时向所有uid推送当前uid在线数及在线页面数
Timer::add(1, function() use ($sender_io) {
// global $uidConnectionMap, $sender_io, $last_online_count, $last_online_page_count;
$online_count_now = count($this->uidConnectionMap);
$online_page_count_now = array_sum($this->uidConnectionMap);
// 只有在客户端在线数变化了才广播,减少不必要的客户端通讯
if($this->last_online_count != $online_count_now || $this->last_online_page_count != $online_page_count_now)
{
$sender_io->emit('update_online_count', "当前<b>{$online_count_now}</b>人在线,共打开<b>{$online_page_count_now}</b>个页面");
$this->last_online_count = $online_count_now;
$this->last_online_page_count = $online_page_count_now;
}
});
});
if(!defined('GLOBAL_START'))
{
Worker::runAll();
}
}
}