安装扩展
手动安装
下载地址
https://www.swoole.com/page/download
cd swoole
phpize
./configure --enable-openssl --with-php-config=/www/server/php/72/bin/php-config
make
sudo make install
修改php.ini加入
extension=swoole.so
宝塔安装
记得去除禁用函数
安装tp扩展
composer require topthink/think-swoole=2.0.*
php public/index.php im/Index/start
再开个终端
lsof -i:39001 //对应设置的端口号
开始使用
控制器
<?php
namespace app\im\controller;
use think\swoole\Server;
use think\db;
class IndexController extends Server
{
protected $host = '0.0.0.0'; //监听所有地址
protected $port = 39001; //监听39001端口
protected $serverType = 'socket';
//开启wss
protected $sockType = SWOOLE_SOCK_TCP | SWOOLE_SSL;
protected $option = [
'ssl_cert_file' => '/www/wwwroot/server.crt',//https时开启
'ssl_key_file' => '/www/wwwroot/server.key',//https时开启
'worker_num' => 4, //设置启动的Worker进程数
'daemonize' => false, //守护进程化(上线改为true)
'max_request' => 10000,
'dispatch_mode' => 2, //固定模式,保证同一个连接发来的数据只会被同一个worker处理
'debug_mode' => 1,
//心跳检测:每60秒遍历所有连接,强制关闭10分钟内没有向服务器发送任何数据的连接
'heartbeat_check_interval' => 60,
'heartbeat_idle_time' => 600
];
//建立连接时回调函数
function onOpen($server, $req)
{
$fd = $req->fd; //客户端标识
$uid = $req->get['uid']; //客户端传递的用户id
$this->bind($uid, $req->fd);
echo "用户{$uid}建立了连接,标识为{$fd}\n";
}
//接收数据时回调函数
public function onMessage($server, $frame)
{
$fd = $frame->fd;
$message = json_decode($frame->data);
$tid = $message->tid;
$uid = $message->uid;
$tfd = $this->getFd($tid);
$data['uid'] = $uid;
$data['message'] = $message->content;
$data['post_time'] = date("m/d H:i", time());
$arr = array('status' => 1, 'message' => 'success', 'data' => $data);
$this->add($uid, $tid, $message->content); //保存消息
$server->push($fd, json_encode($arr));
$fds = []; //所有在线的用户(打开聊天窗口的用户)
foreach ($server->connections as $fd) {
array_push($fds, $fd);
}
//推送给接收者
if (in_array($tfd, $fds)) {
$server->push($tfd, json_encode($arr));
}
//推送给全部连接用户
// foreach($server->connections as $fd) {
// $server->push($fd, json_encode($arr));
// }
}
public function add($fid, $tid, $content)
{
$arr = ['fid' => $fid, 'tid' => $tid, 'content' => $content, 'time' => date("y/m/d H:i", time())];
Db::name('msg')->insertGetId($arr);
}
public function getFd($uid)
{
//$data = Db::name('friends')->where('uid', $uid)->find();
$data = cache('uid' . $uid);
return $data['fid'];
}
public function bind($uid, $fd)
{
$value = ['uid' => $uid, 'fid' => $fd];
cache('uid' . $uid, $value, 1800);
//Db::name('friends')->insert($value, true);
return true;
}
//连接关闭时回调函数
public function onClose($server, $fd)
{
Db::name('fd')->where('fid', $fd)->delete();
}
}
前端
<!DOCTYPE html>
<html xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title>swoole</title>
<script src="__TMPL__/demo/public/assets/js/vue.js"></script>
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/layer/3.1.0/layer.js"></script>
</head>
<body>
<div id="app">
<ol>
<li v-for="message in messages">
{{message.message}} -- {{message.post_time}}
</li>
</ol>
<input v-model="message">
<button v-on:click="sentMessage">发送</button>
</div>
<script>
var client = null;
var uid = 2; //当前用户id
var tid = 1; //接受消息用户ID
var app = new Vue({
el: '#app',
data: {
message: 'Hello swoole!',
messages: []
},
methods: {
sentMessage: function () {
if (this.message == null || this.message == "") {
layer.msg('内容为空', {
shade: 0.1,
icon: 2,
time: 600
});
return false;
} else {
var Data = {
content: this.message,
uid: uid,
tid: tid,
}
client.send(JSON.stringify(Data));
this.message = '';
}
}
}
});
client = new WebSocket("wss://你的域名:39001?uid=" + uid);
client.onopen = function () {
layer.msg('服务器连接成功', {
shade: 0.1,
icon: 1,
time: 600
});
};
client.onerror = function () {
layer.msg('服务器连接失败', {
shade: 0.1,
icon: 2,
time: 600
});
};
client.onmessage = function (evt) {
var data = JSON.parse(evt.data);
console.log(data);
//错误提示
if (data.status != 1) {
layer.alert(data.message, {
icon: 2
});
return;
}
//消息返回
if (data.status == 1 && data.data.message != '') {
app.messages.push(data.data);
}
};
client.onclose = function (res) {
console.log(res)
};
</script>
</body>
</html>