在网上百度了好多关于这一块的,都没有找到完整的教程,这个是我自己写,完完全全可以实现,分享出来给需要的人
PHPSocket.IO手册链接:https://www.workerman.net/phpsocket_io
1.安装
cd到项目的根目录,执行安装
composer require workerman/phpsocket.io
2.入口文件
也是在项目根目录,创建server.php文件,写入下面代码
<?php
define('APP_PATH', __DIR__ . '/application/');
define('BIND_MODULE','socketio/Server/index');
// 加载框架引导文件
require __DIR__ . '/thinkphp/start.php';
3.创建控制器文件,也是第2个步骤的socketio/Server/index
├─application 应用目录
│ ├─socketio 新创建目录
│ │ ├─controller
│ │ │ ├─Server.php 启动文件
4.在Server.php文件写入下面代码
<?php
namespace app\socketio\controller;
require_once VENDOR_PATH . "workerman/phpsocket.io/src/autoload.php";
use Workerman\Worker;
use Workerman\Timer;
use PHPSocketIO\SocketIO;
use Workerman\Protocols\Http\Request;
use Workerman\Connection\TcpConnection;
class Server
{
public function index()
{
// 全局数组保存uid在线数据
$uidConnectionMap = array();
// 记录最后一次广播的在线用户数
$last_online_count = 0;
// 记录最后一次广播的在线页面数
$last_online_page_count = 0;
$io = new SocketIO(2120);//socket的端口
// 客户端发起连接事件时,设置连接socket的各种事件回调
$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($uidConnectionMap[$uid]))
{
$uidConnectionMap[$uid] = 0;
}
// 这个uid有++$uidConnectionMap[$uid]个socket连接
++$uidConnectionMap[$uid];
// 将这个连接加入到uid分组,方便针对uid推送数据
$socket->join($uid);
$socket->uid = $uid;
// 更新这个socket对应页面的在线数据
//$socket->emit('update_online_count', "当前<b>{$last_online_count}</b>人在线,共打开<b>{$last_online_page_count}</b>个页面");
});
// 当客户端断开连接是触发(一般是关闭网页或者跳转刷新导致)
$socket->on('disconnect', function () use($socket) {
if(!isset($socket->uid))
{
return;
}
global $uidConnectionMap, $io;
// 将uid的在线socket数减一
if(--$uidConnectionMap[$socket->uid] <= 0)
{
unset($uidConnectionMap[$socket->uid]);
}
});
});
// 当$sender_io启动后监听一个http端口,通过这个端口可以给任意uid或者所有uid推送数据
$io->on('workerStart', function () use ($io) {
$inner_http_worker = new Worker('http://0.0.0.0:7064');//这里IP不用改变,用的内网通讯,端口不能与socket端口想通
$inner_http_worker->onMessage = function (TcpConnection $http_connection, Request $request) use ($io) {
global $uidConnectionMap;
$post = $request->post();
$post = $post ? $post : $request->get();
// 推送数据的url格式 type=publish&to=uid&content=xxxx
switch(@$post['type']){
case 'publish':
$to = @$post['to'];
$post['content'] = htmlspecialchars(@$post['content']);
// 有指定uid则向uid所在socket组发送数据
if($to){
$io->to($to)->emit('new_msg', $post['content']);
// 否则向所有uid推送数据
}else{
$io->emit('new_msg', @$post['content']);
}
// http接口返回,如果用户离线socket返回fail
if($to && !isset($uidConnectionMap[$to])){
return $http_connection->send('offline');
}else{
return $http_connection->send('ok');
}
}
return $http_connection->send('fail');
};
$inner_http_worker->listen();
});
Worker::runAll();
}
}
5.客户端链接:
<script src='http://cdn.bootcss.com/socket.io/1.3.7/socket.io.js'></script>
var socket = io('http://laodiyuncha.com:2120');
var uid = 'user_1';//这个uid根据自己的项目自定义
socket.on('connect', function(){
socket.emit('login', uid);
});
socket.on('new_msg', function(data){
console.log('推送过来的消息:'+data);
});
6.php推送:
// 推送的url地址,使用自己的服务器地址
$push_api_url = "http://0.0.0.0:7064";
$post_data = array(
"type" => "publish",
"content" => "这个是推送的测试数据",
);
$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 );
var_export($return);
7.启动服务
cd到项目根目录
php server.php start 启动
php server.php stop 停止
php server.php restart 重启
php server.php status 当前服务状态
注意点:
一定要开放2120和7064端口,否则连接不了,会显示跨域,你也可以定义其他端口
项目根目录不是public,指的是public同级目录
👍