PHPSocket.IO 是什么?

  1. PHPSocket.IO是PHP版本的Socket.IO服务端实现,基于workerman开发,用于替换node.js版本Socket.IO服务端。

  2. PHPSocket.IO底层采用websocket协议通讯,如果客户端不支持websocket协议, 则会自动采用http长轮询的方式通讯。

  3. 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安装

  1. composer require workerman/phpsocket.io

应用案例

Nginx 主机配置

    1. server {

 

    1. listen 443 ssl http2;

 

    1. server_name www.tinywan.com;

 

    1. ssl_certificate letsencrypt/iot.tinywan.com/full_chain.pem;

 

    1. ssl_certificate_key letsencrypt/iot.tinywan.com/private.key;

 

    1. set $root_path /var/www/iot.tinywan.com/public;

 

    1. root $root_path;

 

    1. more_set_headers "X-Frame-Options: SAMEORIGIN";

 

    1.  

 

    1. location / {

 

    1. if (!-e $request_filename) {

 

    1. rewrite ^(.*)$ /index.php?s=/$1 last;

 

    1. break;

 

    1. }

 

    1. }

 

 

    1.  

 

    1. # SocketIO 配置

 

    1. location /socket.io {

 

    1. proxy_pass http://127.0.0.1:2120;

 

    1. proxy_http_version 1.1;

 

    1. proxy_set_header Upgrade $http_upgrade;

 

    1. proxy_set_header Connection "Upgrade";

 

    1. proxy_set_header X-Real-IP $remote_addr;

 

    1. }

 

    1. }

 

服务端完整代码

    1. <?php

 

    1. namespace apphttpcontroller;

 

    1.  

 

    1. use PHPSocketIOSocketIO;

 

    1. use thinkfacadeLog;

 

    1. use WorkermanWorker;

 

    1.  

 

    1. class Server

 

    1. {

 

    1. /**

 

    1. * @author: Tinywan(Shaobo Wan)

 

    1. * @time: 2019/4/22 19:51

 

    1. */

 

    1. public function server()

 

    1. {

 

    1. // 全局数组保存uid在线数据

 

    1. $uidConnectionMap = array();

 

    1. // 记录最后一次广播的在线用户数

 

    1. $last_online_count = 0;

 

    1. // 记录最后一次广播的在线页面数

 

    1. $last_online_page_count = 0;

 

    1. // PHPSocketIO服务

 

    1. $sender_io = new SocketIO(2120);

 

    1. // 客户端发起连接事件时,设置连接socket的各种事件回调

 

    1. $sender_io->on('connection', function ($socket) {

 

    1. Log::info('客户端发起连接事件 ');

 

    1. // 当客户端断开连接是触发(一般是关闭网页或者跳转刷新导致)

 

    1. $socket->on('login', function ($uid) use ($socket) {

 

    1. Log::info('客户端登录uid ' . $uid);

 

    1. global $uidConnectionMap, $last_online_count, $last_online_page_count;

 

    1. // 已经登录过了

 

    1. if (isset($socket->uid)) {

 

    1. return;

 

    1. }

 

    1. // 更新对应uid的在线数据

 

    1. $uid = (string)$uid;

 

    1. if (!isset($uidConnectionMap[$uid])) {

 

    1. $uidConnectionMap[$uid] = 0;

 

    1. }

 

    1. // 这个uid有++$uidConnectionMap[$uid]个socket连接

 

    1. ++$uidConnectionMap[$uid];

 

    1. // 将这个连接加入到uid分组,方便针对uid推送数据

 

    1. $socket->join($uid);

 

    1. $socket->uid = $uid;

 

    1. });

 

    1. // 当客户端断开连接是触发(一般是关闭网页或者跳转刷新导致)

 

    1. $socket->on('disconnect', function () use ($socket) {

 

    1. Log::info('客户端断开 ' . json_encode($socket));

 

    1. if (!isset($socket->uid)) {

 

    1. return;

 

    1. }

 

    1. global $uidConnectionMap, $sender_io;

 

    1. // 将uid的在线socket数减一

 

    1. if (--$uidConnectionMap[$socket->uid] <= 0) {

 

    1. unset($uidConnectionMap[$socket->uid]);

 

    1. }

 

    1. });

 

    1. });

 

    1. // 当$sender_io启动后监听一个http端口,通过这个端口可以给任意uid或者所有uid推送数据

 

    1. $sender_io->on('workerStart', function () use ($sender_io) {

 

    1. // 监听一个http端口

 

    1. $inner_http_worker = new Worker('http://0.0.0.0:2121');//这里IP不用改变,用的内网通讯,端口不能与socket端口想通

 

    1. $inner_http_worker->onMessage = function ($http_connection, $data) use ($sender_io) {

 

    1. $postData = $data['post'];

 

    1. $to = $postData['to'] ?? '';

 

    1. Log::info('发送到用户to ' . json_encode($to));

 

    1. $content = htmlspecialchars($postData['content']);

 

    1. // 有指定uid则向uid所在socket组发送数据

 

    1. if ($to) {

 

    1. $sender_io->to($to)->emit('new_msg', $content);

 

    1. } else {

 

    1. // 否则向所有uid推送数据

 

    1. $sender_io->emit('new_msg', $content);

 

    1. }

 

    1. // http接口返回,如果用户离线socket返回fail

 

    1. if ($to && !isset($uidConnectionMap[$to])) {

 

    1. return $http_connection->send('offline');

 

    1. } else {

 

    1. return $http_connection->send('ok');

 

    1. }

 

    1. };

 

    1. // 执行监听

 

    1. $inner_http_worker->listen();

 

    1. });

 

    1. Worker::runAll();

 

    1. }

 

    1. }

 

1、启动服务端端: php web_msg.php start-d

    1. $ php web_msg.php start -d

 

    1. Workerman[web_msg.php] start in DAEMON mode

 

    1. ------------------------------------------- WORKERMAN -------------------------------------------

 

    1. Workerman version:3.5.20 PHP version:7.2.9

 

    1. -------------------------------------------- WORKERS --------------------------------------------

 

    1. proto user worker listen processes status

 

    1. tcp www PHPSocketIO socketIO://0.0.0.0:2120 1 [OK]

 

2、发送消息

    1. function send_web_msg($to_uid = 1, $content)

 

    1. {

 

    1. if (empty($content)) {

 

    1. return ["error_code" => 404, "reason" => '缺少参数'];

 

    1. }

 

    1. $push_api_url = "http://127.0.0.1:2121/";

 

    1. $post_data = [

 

    1. "type" => "publish",

 

    1. "content" => $content,

 

    1. "to" => $to_uid

 

    1. ];

 

    1. $ch = curl_init();

 

    1. curl_setopt($ch, CURLOPT_URL, $push_api_url);

 

    1. curl_setopt($ch, CURLOPT_POST, 1);

 

    1. curl_setopt($ch, CURLOPT_HEADER, 0);

 

    1. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

 

    1. curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);

 

    1. curl_setopt($ch, CURLOPT_HTTPHEADER, array("Expect:"));

 

    1. $return = curl_exec($ch);

 

    1. curl_close($ch);

 

    1. return $return;

 

    1. }

 

    1.  

 

    1. send_web_msg(1, "哈喽,Tinywan先生");

 

客户端完整代码

html 代码

  1. <div><p id="notice-content" style="float: left">系统公告</p></div>

JS 代码

    1. <script src='https://cdn.bootcss.com/socket.io/2.0.3/socket.io.js'></script>

 

    1. <script src="https://cdn.bootcss.com/notify.js/3.0.0/notify.js"></script>

 

    1. <script>

 

    1. $(document).ready(function () {

 

    1. $uid = "1";

 

    1. var socket = io("https://www.tinywan.com", { path: '/socket.io' });

 

    1. socket.on('connect', function () {

 

    1. console.log('连接成功');

 

    1. socket.emit('login', $uid);

 

    1. });

 

    1. socket.on('new_msg', function (msg) {

 

    1. console.log('系统消息:' + msg);

 

    1. $('#notice-content').html('系统提示:' + msg);

 

    1. $('.notification.sticky').notify();

 

    1. });

 

    1. });

 

    1. </script>

 

效果图

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。