`<?php `
`use` `Workerman\Worker;`
`use` `Workerman\WebServer;`
`use` `Workerman\Lib\Timer;`
`use` `PHPSocketIO\SocketIO;`
`include` `__DIR__ .` `'/vendor/autoload.php'``;`
`// 全局数组保存uid在线数据,一维数组,键为房间加上-uid,例如,web1-2924,为web_video的id为1的房间的2924用户`
`$uidConnectionMap` `= [];`
`// 全局数组保存房间在线数据,二维数组`
`$roomMap` `= [];`
`// 记录最后一次广播的在线用户数`
`$last_online_count` `= [];`
`// 记录最后一次广播的在线页面数`
`$last_online_page_count` `= [];`
`// PHPSocketIO服务`
`$socketIoPort` `= 2130;`
`$sender_io` `=` `new` `SocketIO(``$socketIoPort``);`
`// 客户端发起连接事件时,设置连接socket的各种事件回调`
`$sender_io``->on(``'connection'``,` `function` `(``$socket``) {`
`// 当客户端发来登录事件时触发`
`$socket``->on(``'login'``,` `function` `(``$uid``,` `$group``,` `$video_type``,` `$video_id``)` `use` `(``$socket``) {`
`global` `$uidConnectionMap``,` `$roomMap``,` `$last_online_count``,` `$last_online_page_count``,` `$socketIoPort``;`
`// 已经登录过了`
`if` `(isset(``$socket``->uid)) {`
`return``;`
`}`
`// 更新对应uid的在线数据`
`$uid` `= (string)``$uid``;`
`// 哪个房间`
`$room` `=` `$video_type` `.` `$video_id``;`
`// 哪个房间的哪个用户`
`$socket``->uid =` `$room` `.` `'-'` `.` `$uid``;`
`if` `(!isset(``$uidConnectionMap``[``$socket``->uid])) {`
`$uidConnectionMap``[``$socket``->uid] = 0;`
`}`
`if` `(!isset(``$roomMap``[``$room``][``$uid``])) {`
`$roomMap``[``$room``][``$uid``] = 0;`
`}`
`// 这个uid有++$uidConnectionMap[$uid]个socket连接`
`++``$uidConnectionMap``[``$socket``->uid];`
`++``$roomMap``[``$room``][``$uid``];`
`// 保存到文件,方便查看`
`$file` `=` `'/tmp/logs/socket/'` `.` `$socketIoPort` `.` `'-'` `. md5(``__FILE__``) .` `'.log'``;`
`if` `(``file_exists``(``$file``)) {`
`$contents` `= @``file_get_contents``(``$file``);`
`}` `else` `{`
`$contents` `=` `''``;`
`}`
`$contents` `.=` `$socket``->uid .` `"\n"``;`
`@``file_put_contents``(``$file``,` `$contents``);`
`if` `(!isset(``$last_online_count``[``$room``])) {`
`$last_online_count``[``$room``] = 0;`
`}`
`if` `(!isset(``$last_online_page_count``[``$room``])) {`
`$last_online_page_count``[``$room``] = 0;`
`}`
`// 将这个连接加入到uid分组,方便针对uid推送数据`
`$socket``->join(``$uid``);` `// 某个人`
`$socket``->join(``$socket``->uid);` `// 某个房间某个人`
`$socket``->join(``$room``);` `// 某个房间`
`$socket``->join(``$group``);` `// 分组,比如客服等`
`$socket``->to(``$room``)->emit(``'update_online_count'``,` `"当前{$last_online_count[$room]}人在线,共打开{$last_online_page_count[$room]}个页面"``);`
`});`
`// 当客户端断开连接是触发(一般是关闭网页或者跳转刷新导致)`
`$socket``->on(``'disconnect'``,` `function` `()` `use` `(``$socket``) {`
`if` `(!isset(``$socket``->uid)) {`
`return``;`
`}`
`global` `$uidConnectionMap``,` `$sender_io``,` `$socketIoPort``;`
`// 将uid的在线socket数减一`
`if` `(--``$uidConnectionMap``[``$socket``->uid] <= 0) {`
`unset(``$uidConnectionMap``[``$socket``->uid]);`
`}`
`// 从文件中删除`
`$file` `=` `'/tmp/logs/socket/'` `.` `$socketIoPort` `.` `'-'` `. md5(``__FILE__``) .` `'.log'``;`
`if` `(``file_exists``(``$file``)) {`
`$contents` `= @``file_get_contents``(``$file``);`
`if` `(``is_string``(``$contents``)) {`
`$arr` `=` `explode``(``"\n"``,` `$contents``);`
`foreach` `(``$arr` `as` `$k` `=>` `$v``) {`
`if` `(``$v` `==` `$socket``->uid) {`
`unset(``$arr``[``$k``]);`
`}`
`}`
`$contents` `= implode(``"\n"``,` `$arr``);`
`@``file_put_contents``(``$file``,` `$contents``);`
`}`
`}` `else` `{`
`$contents` `=` `''``;`
`}`
`@``file_put_contents``(``$file``,` `$contents``);`
`});`
`});`
`// 当$sender_io启动后监听一个http端口,通过这个端口可以给任意uid或者所有uid推送数据`
`// to是追加的关系,比如->to(1)->to(2),那么会向1和2推送消息`
`$sender_io``->on(``'workerStart'``,` `function` `() {`
`// 监听一个http端口`
`$inner_http_worker` `=` `new` `Worker(``'http://0.0.0.0:2132'``);`
`// 当http客户端发来数据时触发`
`$inner_http_worker``->onMessage =` `function` `(``$http_connection``,` `$data``) {`
`/** @var \Workerman\Connection\TcpConnection $http_connection */`
`global` `$uidConnectionMap``;`
`$_POST` `=` `$_POST` `?` `$_POST` `:` `$_GET``;`
`$video_type` `=` `$_POST``[``'video_type'``] = isset(``$_POST``[``'video_type'``]) ?` `$_POST``[``'video_type'``] :` `''``;`
`$video_id` `=` `$_POST``[``'video_id'``] = isset(``$_POST``[``'video_id'``]) ?` `$_POST``[``'video_id'``] :` `''``;`
`$room` `=` `$video_type` `.` `$video_id``;`
`// 推送数据的url格式 type=publish&to=uid&content=xxxx`
`require` `__DIR__ .` `'/logic.php'``;`
`return` `$http_connection``->send(``'fail'``);`
`};`
`// 执行监听`
`$inner_http_worker``->listen();`
`// 一个定时器,定时向所有uid推送当前uid在线数及在线页面数`
`Timer::add(1,` `function` `() {`
`global` `$uidConnectionMap``,` `$roomMap``,` `$sender_io``,` `$last_online_count``,` `$last_online_page_count``,` `$use_id``;`
`foreach` `(``$roomMap` `as` `$room` `=>` `$uids``) {`
`$online_count_now` `=` `count``(``$uids``);`
`$online_page_count_now` `=` `array_sum``(``$uids``);`
`// 只有在客户端在线数变化了才广播,减少不必要的客户端通讯`
`if` `(``$last_online_count``[``$room``] !=` `$online_count_now` `||` `$last_online_page_count``[``$room``] !=` `$online_page_count_now``) {`
`$sender_io``->to(``$room``)->emit(``'update_online_count'``,` `"当前{$online_count_now}人在线,共打开{$online_page_count_now}个页面"``);`
`$last_online_count``[``$room``] =` `$online_count_now``;`
`$last_online_page_count``[``$room``] =` `$online_page_count_now``;`
`}`
`}`
`});`
`});`
`if` `(!defined(``'GLOBAL_START'``)) {`
`Worker::runAll();`
`}`