PHP系列 | PHP跨平台实时通讯框架 Socket.IO 的应用
时间:2022-06-26
本文章向大家介绍PHP系列 | PHP跨平台实时通讯框架 Socket.IO 的应用,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
PHPSocket.IO 是什么?
- PHPSocket.IO是PHP版本的Socket.IO服务端实现,基于workerman开发,用于替换node.js版本Socket.IO服务端。
- PHPSocket.IO底层采用websocket协议通讯,如果客户端不支持websocket协议, 则会自动采用http长轮询的方式通讯。
- PHPSocket.IO实现的Polling通信机制包括Adobe Flash Socket、AJAX长轮询、JSONP轮询等。具体采用哪种机制通讯对于开发者完全透明, 开发者使用的是统一的接口。
设计的目标
利用PHP构建能够在不同浏览器和移动设备上良好运行的实时应用,如实时分析系统、在线聊天室、在线客服系统、评论系统、WebIM等。
PHPSocket.IO与workerman的区别是:
PHPSocket.IO基于workerman开发,workerman有的特性PHPSocket.IO都支持。PHPSocket.IO最大的优势是对各种浏览器的兼容性更好。
文档&&安装
文档仓库:https://github.com/walkor/phpsocket.io 使用composer安装
composer require workerman/phpsocket.io
应用案例
Nginx 主机配置
server {
listen 443 ssl http2;
server_name www.tinywan.com;
ssl_certificate letsencrypt/iot.tinywan.com/full_chain.pem;
ssl_certificate_key letsencrypt/iot.tinywan.com/private.key;
set $root_path /var/www/iot.tinywan.com/public;
root $root_path;
more_set_headers "X-Frame-Options: SAMEORIGIN";
location / {
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php?s=/$1 last;
break;
}
}
# SocketIO 配置
location /socket.io {
proxy_pass http://127.0.0.1:2120;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header X-Real-IP $remote_addr;
}
}
服务端完整代码
<?php
namespace apphttpcontroller;
use PHPSocketIOSocketIO;
use thinkfacadeLog;
use WorkermanWorker;
class Server
{
/**
* @author: Tinywan(Shaobo Wan)
* @time: 2019/4/22 19:51
*/
public function server()
{
// 全局数组保存uid在线数据
$uidConnectionMap = array();
// 记录最后一次广播的在线用户数
$last_online_count = 0;
// 记录最后一次广播的在线页面数
$last_online_page_count = 0;
// PHPSocketIO服务
$sender_io = new SocketIO(2120);
// 客户端发起连接事件时,设置连接socket的各种事件回调
$sender_io->on('connection', function ($socket) {
Log::info('客户端发起连接事件 ');
// 当客户端断开连接是触发(一般是关闭网页或者跳转刷新导致)
$socket->on('login', function ($uid) use ($socket) {
Log::info('客户端登录uid ' . $uid);
global $uidConnectionMap, $last_online_count, $last_online_page_count;
// 已经登录过了
if (isset($socket->uid)) {
return;
}
// 更新对应uid的在线数据
$uid = (string)$uid;
if (!isset($uidConnectionMap[$uid])) {
$uidConnectionMap[$uid] = 0;
}
// 这个uid有++$uidConnectionMap[$uid]个socket连接
++$uidConnectionMap[$uid];
// 将这个连接加入到uid分组,方便针对uid推送数据
$socket->join($uid);
$socket->uid = $uid;
});
// 当客户端断开连接是触发(一般是关闭网页或者跳转刷新导致)
$socket->on('disconnect', function () use ($socket) {
Log::info('客户端断开 ' . json_encode($socket));
if (!isset($socket->uid)) {
return;
}
global $uidConnectionMap, $sender_io;
// 将uid的在线socket数减一
if (--$uidConnectionMap[$socket->uid] <= 0) {
unset($uidConnectionMap[$socket->uid]);
}
});
});
// 当$sender_io启动后监听一个http端口,通过这个端口可以给任意uid或者所有uid推送数据
$sender_io->on('workerStart', function () use ($sender_io) {
// 监听一个http端口
$inner_http_worker = new Worker('http://0.0.0.0:2121');//这里IP不用改变,用的内网通讯,端口不能与socket端口想通
$inner_http_worker->onMessage = function ($http_connection, $data) use ($sender_io) {
$postData = $data['post'];
$to = $postData['to'] ?? '';
Log::info('发送到用户to ' . json_encode($to));
$content = htmlspecialchars($postData['content']);
// 有指定uid则向uid所在socket组发送数据
if ($to) {
$sender_io->to($to)->emit('new_msg', $content);
} else {
// 否则向所有uid推送数据
$sender_io->emit('new_msg', $content);
}
// http接口返回,如果用户离线socket返回fail
if ($to && !isset($uidConnectionMap[$to])) {
return $http_connection->send('offline');
} else {
return $http_connection->send('ok');
}
};
// 执行监听
$inner_http_worker->listen();
});
Worker::runAll();
}
}
1、启动服务端端: php web_msg.php start-d
$ php web_msg.php start -d
Workerman[web_msg.php] start in DAEMON mode
------------------------------------------- WORKERMAN -------------------------------------------
Workerman version:3.5.20 PHP version:7.2.9
-------------------------------------------- WORKERS --------------------------------------------
proto user worker listen processes status
tcp www PHPSocketIO socketIO://0.0.0.0:2120 1 [OK]
2、发送消息
function send_web_msg($to_uid = 1, $content)
{
if (empty($content)) {
return ["error_code" => 404, "reason" => '缺少参数'];
}
$push_api_url = "http://127.0.0.1:2121/";
$post_data = [
"type" => "publish",
"content" => $content,
"to" => $to_uid
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $push_api_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Expect:"));
$return = curl_exec($ch);
curl_close($ch);
return $return;
}
send_web_msg(1, "哈喽,Tinywan先生");
客户端完整代码
html 代码
<div><p id="notice-content" style="float: left">系统公告</p></div>
JS 代码
<script src='https://cdn.bootcss.com/socket.io/2.0.3/socket.io.js'></script>
<script src="https://cdn.bootcss.com/notify.js/3.0.0/notify.js"></script>
<script>
$(document).ready(function () {
$uid = "1";
var socket = io("https://www.tinywan.com", { path: '/socket.io' });
socket.on('connect', function () {
console.log('连接成功');
socket.emit('login', $uid);
});
socket.on('new_msg', function (msg) {
console.log('系统消息:' + msg);
$('#notice-content').html('系统提示:' + msg);
$('.notification.sticky').notify();
});
});
</script>
效果图
- jboss EAP 6.2 + Message Drive Bean(MDB) 整合IBM Webshpere MQ 7.5
- 通过jenkins API去build一个job
- Django---分页器、中间件
- 启动jenkins服务错误
- 如果未来的AI拥有意识,你舍得不理它吗?
- centos下安装python3
- jboss:在standalone.xml中设置系统属性(system-properties)
- iptables
- Django-form表单
- 比较git commit 两个版本之间次数
- eclipse: workspace出错导致无法启用的解决
- 【node错误】/usr/bin/env: node: No such file or directory
- Django比较相等或者不相等的模板语法ifequal / ifnotequal
- 使用testNGListenter来自定义日志
- php概述
- php教程
- php环境搭建
- PHP书写格式
- php变量
- php常量
- PHP注释
- php数组
- php字符串 string
- PHP整型 integer
- PHP浮点型 float
- php布尔型
- php数据类型之数组
- php数据类型之对象
- php数据类型之null
- php数据类型之间的转换
- php运算符
- php表达式
- PHP循环控制
- PHP流程控制
- php函数
- php全局变量
- PHP魔术变量
- php命名空间
- php 日期
- PHP包含文件
- php文件
- PHP 文件上传
- php Cookies
- php Sessions
- php email
- php安全email
- php错误处理
- PHP异常处理
- php过滤器
- PHP 高级过滤器
- php json
- php 表单
- PHP MySQL 简介
- PHP 连接 MySQL
- php创建数据库
- php 创建表
- php mysq 插入数据
- PHP MySQL 插入多条数据
- PHP MySQL 预处理语句
- php mysql 读取数据
- php mysql where
- PHP MySQL Order By
- PHP MySQL Update
- PHP MySQL Delete
- php ODBC
- java 字节流入门(内存数组流->文件流)
- 视频高速上云网关/网络穿透EasyNTS智能组网服务平台ini配置文件丢失如何处理?
- 结构与算法(05):二叉树与多叉树
- 树莓派综合项目2:智能小车(二)tkinter图形界面控制
- 虚拟机系列 | JVM运行时数据区
- 虚拟机系列 | 执行引擎和垃圾回收
- 在Linux系统中编译ARM版EasyNTS上云网关服务报undefined错误的解决方案
- 从全备中恢复单库或单表,小心有坑!
- Zookeeper安装以及常用操作
- Codeforces Round 671 (Div. 2) A-D
- 程序中并没有走缓存,为什么执行时间短了
- ES 常用Linux查询命令汇总
- PostgreSql 怎么获取数据库中关键系统信息(一)
- 树莓派基础实验36:通用串口通信实验
- PIMPL:休想窥探我的隐私!