Swoole:面向生产环境的 PHP 异步网络通信引擎
使 PHP 开发人员可以编写高性能的异步并发 TCP、UDP、Unix Socket、HTTP,WebSocket 服务。Swoole 可以广泛应用于互联网、移动通信、企业软件、云计算、网络游戏、物联网(IOT)、车联网、智能家居等领域。使用 PHP Swoole 作为网络通信框架,可以使企业 IT 研发团队的效率大大提升,更加专注于开发创新产品。
新建PushServer.php
代码语言:javascript复制<?php
/**
* Created by PhpStorm.
* User: zhengbingdong
* Date: 2020/08/15
* Time: 01:06
*/
class PushServer
{
private static $instance;
private static $server;
public $messageHandler;//处理消息的对象
//不能够在类外面创建该对象的实例
private function __construct()
{
//>>1.创建websocket对象
self::$server = new swoole_websocket_server('0.0.0.0', 9502);
//>>2.注册事件
self::$server->on('open', [$this, 'onOpen']);//将当前类的onOpen方法作为open的事件处理函数
self::$server->on('message', [$this, 'onMessage']);
self::$server->on('close', [$this, 'onClose']);
self::$server->on('workerStart',[$this,'onWorkerStart']);
}
//当客户端连上之后要执行的方法
public function onOpen($server, $req)
{
echo "connection open: {$req->fd}n";
}
//客户端向服务器发送消息要执行的方法
public function onMessage($server, $frame)
{
//将传输的json转成数组
$data = json_decode($frame->data,true);
//检查方法是否存在
if (method_exists($this->messageHandler,$data['cmd'])){
call_user_func([$this->messageHandler,$data['cmd']],self::$server,$data['data']);
}else{
$outMessage = json_encode([
'status' => 'error',
'msg' => '非法操作'
]);
echo $outMessage."n";
self::$server->push($frame->fd, $outMessage);
}
}
//客户端和服务器端断开连接时执行的方法
public function onClose($server,$fd)
{
$online = [];
foreach ($server->connections as $clientId) {
array_push($online, $clientId);
$outMessage = json_encode(
[
'type' => 'close',
'fid' => $clientId,
'online' => $online,
'num' => count($server->connections)
]
);
self::$server->push($clientId, $outMessage);
}
echo "当前服务器共有 " . count($server->connections) . " 个连接n";
echo '客户端或服务器断开连接'.$fd."n";
}
//服务器启动之后执行
public function onWorkerStart(){
echo 'onWorkerStart----------'.date('Y-m-d H:i:s')."n";
require './MessageHandler.php';
$this->messageHandler = new MessageHandler();
}
public static function getInstance()
{
if (!self::$instance instanceof self) {
self::$instance = new self();
}
return self::$instance;
}
public function start()
{
self::$server->start();
}
}
PushServer::getInstance()->start();//启动推送服务器
新建MessageHandler.php
代码语言:javascript复制<?php
/**
* Created by PhpStorm.
* User: zhengbingdong
* Date: 2020/08/15
* Time: 01:06
*/
class MessageHandler
{
public function join($server, $data)
{
foreach ($server->connections as $fd) {
$outMessage = json_encode(
[
'type' => 'join',
'client_id' => $fd,
'name' => $data['name'],
'num' => count($server->connections)
]
);
$server->push($fd, $outMessage);
}
}
public function sendMessage($server, $data){
foreach ($server->connections as $fd) {
$outMessage = json_encode(
[
'name' => $data['name'],
'content' => $data['content']
]
);
$server->push($fd, $outMessage);
}
}
public function changeNickName($server, $data){
foreach ($server->connections as $fd) {
$outMessage = json_encode(
[
'type' => 'changeNickName',
'before' => $data['before'],
'after' => $data['after']
]
);
$server->push($fd, $outMessage);
}
}
public function outLine(){
echo '-------------------------离开了';
}
}
新建聊天室页面
代码语言:javascript复制<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>匿名即时聊天室</title>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
</head>
<style type="text/css" media="all">
body {
padding: 0;
margin: 0;
}
#online {
width: 100%;
margin: 0 auto;
}
#messgae {
background: #eee;
padding: 5px;
margin-bottom: 15px;
height: 380px;
overflow: scroll;
}
#online-num {
font-size: 15px;
padding-left: 10px;
}
#socket {
background: #f5f5f5;
padding: 20px;
}
#name {
width: 98%;
}
#content {
width: 98%;
}
#sender {
width: 100%;
}
</style>
<body>
<div id="online">
<div id="messgae">
<h3 id="title">匿名聊天室<span id="online-num">当前在线<span id="num"></span>人</span></h3>
</div>
<div id="socket">
<p>网名:
<input type="text" id="name" value="">
</p>
<p>内容:
<textarea name="" id="content" rows="8" cols="40"></textarea>
</p>
<p>
<input type="submit" name="" id="sender" value="发送" />
</p>
</div>
</div>
<script>
var cookie = {
set: function (key, val, time) { //设置cookie方法
var date = new Date(); //获取当前时间
var expiresDays = time; //将date设置为n天以后的时间
date.setTime(date.getTime() expiresDays * 24 * 3600 * 1000); //格式化为cookie识别的时间
document.cookie = key "=" val ";expires=" date.toGMTString(); //设置cookie
},
get: function (key) { //获取cookie方法
/*获取cookie参数*/
var getCookie = document.cookie.replace(/[ ]/g, ""); //获取cookie,并且将获得的cookie格式化,去掉空格字符
var arrCookie = getCookie.split(";") //将获得的cookie以"分号"为标识 将cookie保存到arrCookie的数组中
var tips; //声明变量tips
for (var i = 0; i < arrCookie.length; i ) { //使用for循环查找cookie中的tips变量
var arr = arrCookie[i].split("="); //将单条cookie用"等号"为标识,将单条cookie保存为arr数组
if (key == arr[0]) { //匹配变量名称,其中arr[0]是指的cookie名称,如果该条变量为tips则执行判断语句中的赋值操作
tips = arr[1]; //将cookie的值赋给变量tips
break; //终止for循环遍历
}
}
return tips;
},
delete: function (key) { //删除cookie方法
var date = new Date(); //获取当前时间
date.setTime(date.getTime() - 10000); //将date设置为过去的时间
document.cookie = key "=v; expires =" date.toGMTString(); //设置cookie
}
};
$(function () {
$('#name').val(cookie.get("userNickname") ? cookie.get("userNickname"):'游客' <?= date('YmdHis'); ?>)
$('#name').blur(function () {
var name = $('#name').val();
var before = cookie.get("userNickname") ? cookie.get("userNickname") : name;
cookie.set("userNickname", name, 24)
websocket.send('{"cmd":"changeNickName","data":{"before":"' before '","after":"' name '"}}');
});
var websocket = new WebSocket("ws://192.168.31.107:9502");
websocket.onopen = function () {
console.log('连接上服务器');
var intNickName = cookie.get("userNickname") ? cookie.get("userNickname") : '游客' <?= date('YmdHis'); ?> ;
cookie.set("userNickname", intNickName, 24);
websocket.send('{"cmd":"join","data":{"name":"' intNickName '"}}');
}
websocket.onmessage = function (event) {
var getName = cookie.get("userNickname");
var data = JSON.parse(event.data);
//console.log(data)
if (data.type == 'join') {
$('#messgae').append('<p>系统提示:' data.name '加入聊天室</p>');
$('#num').text(data.num);
} else if (data.type == 'close') {
$('#messgae').append('<p>系统提示:' data.fid '离开了聊天室</p>');
} else if (data.type == 'changeNickName') {
$('#messgae').append('<p>系统提示:' data.before '更改了网名为《' data.after '》</p>');
} else {
$('#messgae').append(
'<p>' data.name ':' data.content '</p>');
}
goBottom();
}
websocket.onclose = function () {
console.log('断开了链接');
}
$('#sender').click(function () {
var name = $('#name').val();
var sendContent = $('#content').val()
websocket.send('{"cmd":"sendMessage","data":{"name":"' name '","content":"' sendContent '"}}');
$('#content').val('');
goBottom();
})
function goBottom(){
var div = document.getElementById('messgae');
div.scrollTop = div.scrollHeight;
}
});
</script>
</body>
</html>