Swoole - webSocket消息服务系统代码设计篇
概述
已经Swoole系列的第二篇知识点了,前一篇主要的针对处理的是方案设计,这一篇主要是代码实现的内容,主要介绍高性能的原因已经实现,编程框架使用EasySwoole。
(资料图片仅供参考)
Swoole 与 EasySwoole
Swoole属于php中的一个超级扩展,它会接管PHP的进程,管理和分配worker,但他依赖 PHP-Cli模式。Swoole和Yaf有相似的地方,它们都是以守护进程的模式、常驻内存的方式达到提高处理性能。
Swoole内置了TCP、UDP、WebSocket、协程、异步、Redis/Mysql链接池等高效开发手段和方法,当然对于新模式也有新的挑战,比如swoole不能使用die,会致使worker滑落,协程使用后要注意使用回调的过程,如果对php的基础知识不了解的同学,可以翻看我之前的php博客里的总结,这里就不过多叙述了。
EasySwoole是一款非常简单上手易操作的Swoole框架,上线2年多以来经得住生产环境的考验,官网文档写的也很详细,还有专门解答的QQ群,大佬们会解答很多问题。
安装EasySwoole框架
之前我使用composer进行安装的(composer是php中管理依赖包的工具,和node里面的npm,python的pip 一样),现在都使用docker镜像直接操作了。
docker pull easyswoole/easyswoole3docker run -ti -p 9501:9501 -p 80:80 --name easyswoole easyswoole/easyswoole3
项目目录结构:
.├── App│ ├── Conf│ ├── Crontab│ ├── HttpController│ │ ├── Api│ │ └── Router.php│ ├── Log│ │ └── LogHandel.php│ ├── Models│ │ ├── ImChatModel.php│ │ ├── ImModel.php│ │ └── PushMsgModel.php│ ├── Parser│ │ └── WebSocketParser.php│ ├── Server│ │ ├── ChangPeiServer│ │ ├── MysqlServer│ │ ├── RedisServer│ │ ├── Server.php│ │ └── WebSocketServer│ ├── Utility│ │ ├── Http│ │ ├── Mall│ │ └── Ws│ ├── WebSocketController│ │ ├── Base.php│ │ ├── Error│ │ ├── V1│ ├── WebSocketEvent.php│ └── WebSocketRoute│ └── ForwardRoute.php├── EasySwooleEvent.php├── Log│ └── swoole.log
注册服务 与启动加载
1.在EasySwooleEvent.php文件中加载初始化需要的Mysql、redis配置文件,所有需要的服务都需要在启动文件中进行注册,才能使用。
public static function loadConf(){ $ConfPath = EASYSWOOLE_ROOT . "/App/Conf/"; $Conf = Config::getInstance(); $files = File::scanDirectory($ConfPath); if (!is_array($files["files"])) { return; } foreach ($files["files"] as $file) { $data = require_once $file; $Conf->setConf(strtolower(basename($file, ".php")), (array)$data); }}
2.注册Mysql连接池,Mysql连接池主要设置参数,
[ "host" => "59.110.162.133", "port" => "3306", "database" => "swoole_msg", //cpwxw2_db_v2 "username" => "work", "password" => "cp2018csq123456", "timeout" => 300, "charset" => "utf8mb4" ], //Mysql连接池配置 "conn_pool" => [ "timeOut" => "3.0", //设置获取连接池对象超时时间 "checkOut" => 30 * 1000, //设置检测连接存活执行回收和创建的周期 "maxidleTime" => 15, //连接池对象最大闲置时间(秒) "maxObjectNumber" => 100, //设置最大连接池存在连接对象数量 "minObjectNumber" => 5, //设置最小连接池存在连接对象数量 "autoPing" => 5, //设置自动ping客户端链接的间隔 ],];
3.注册redis链接池
use \EasySwoole\Redis\Config\RedisConfig;use \EasySwoole\RedisPool\RedisPool;$redisConf = GlobalConfig::getInstance()->getConf("redis");RedisPool::getInstance()->register(new RedisConfig($redisConf),"redis");
4.注册自定义log
use \EasySwoole\EasySwoole\Logger;Logger::getInstance(new \App\Log\LogHandel());
5.我的项目里还使用了crontab模块
use Swoole\Coroutine\Scheduler;use EasySwoole\EasySwoole\Crontab\Crontab;//用户通知队列Crontab::getInstance()->addTask(\App\Crontab\PushUserNoticeMsg::class);
6.添加热启动
Swoole的服务属于常驻内存加载类型的服务,所以每次修改代码后都需要重启服务,所以为了方便,添加了热加载目录,热加载原理就是当检测到指定目录有代码更新时,用传递信号的方式进行,指挥进程进行重新加载。
$hotReloadOptions = new \EasySwoole\HotReload\HotReloadOptions;$hotReload = new \EasySwoole\HotReload\HotReload($hotReloadOptions);$hotReloadOptions->setMonitorFolder([EASYSWOOLE_ROOT . "/App"]);$server = ServerManager::getInstance()->getSwooleServer();$hotReload->attachToServer($server);
7.启动/停止服务,参数说明
-mode 说明启动服务类型
-d 以守护进程的方式
php easyswoole server start -mode=websocket -dphp easyswoole server stop
异步和 DB(Redis/Mysql)使用
1.高性能的异步操作
如果是不依赖于结果的计算,异步操作提高性能的有效手段之一,异步操作不需要等待结果,更好的利用CPU和I/O传输。
use EasySwoole\EasySwoole\Task\TaskManager;TaskManager::getInstance()->async(function () use ($tableName,$data) { // todo code ...});
2.Redis/Mysql使用
在高并发情况下,资源浪费的占用时间越短越好,可以提高程序的服务效率。在ORM默认情况下是使用defer方法获取pool内的连接资源,并在协程退出时自动归还,在此情况下,在带来便利的同时,会造成不必要资源的浪费。
我们可以使用invoke方式,让ORM查询结束后马上归还资源,可以提高资源的利用率。
Mysql的使用Demo.
DbManager::getInstance()->invoke(function (ClientInterface $client)use ($where, $tableName, $count) { $pushMsgModel = PushMsgModel::invoke($client); $pushMsgObj = $pushMsgModel->tableName($tableName) ->field(["push_id"]) ->get($where);}, self::MYSQL_CONN_NAME);
Redis的使用Demo.
## invoke方式public function setAuthorFd(int $uid, int $fd){ RedisPool::invoke(function (Redis $redis) use ($fd, $uid) { $sRet = $redis->zAdd(self::PUSH_MSG_AUTHOR_NOTICE_SYSTEM, $uid, $fd); }, self::REDIS_CONN_NAME);}## defer方式$redis = \EasySwoole\RedisPool\RedisPool::defer("redis");$data = $redis->lRange(self::PUSH_MSG_COMMENT_DELAY_LISTS, 0, 1000);
WebSocket服务
1.WebSocket协议是什么
WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。
在没有WebSocket协议之前,在网页中,实现一个聊天室只能使用ajax 不断轮询,请求服务器是否有数据产生,而这样的实现方法会出现一系列的问题:
如果轮询时间间隔太短,会导致客户端和服务端在一个时间段内不断的进行http tcp的握手/挥手动作和http 请求头,响应头的传输,大量消耗服务器资源,如果用户量大的情况,会造成服务器的繁忙以至于宕机客户端每次只能通过发送http 请求获得服务器是否有数据返回,且数据的及时性无法保证正因为在这种情况下,所以WebSocket出现了,它只需要一次http握手,就可以保持一个长连接,使得服务器可以主动发送消息给客户端,大大减少了轮询机制的消耗。
2.WebSocket协议实现原理
在实现websocket连线过程中,需要通过浏览器发出websocket连线请求,然后服务器发出回应,这个过程通常称为握手 。
在 WebSocket API,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。在此WebSocket 协议中,为我们实现即时服务带来了两大好处:
Header: 互相沟通的Header是很小的-大概只有 2 BytesServer Push: 服务器的推送,服务器不再被动的接收到浏览器的请求之后才返回数据,而是在有新数据时就主动推送给浏览器。//$fd,指的是系统里的文件描述符fduse EasySwoole\EasySwoole\ServerManager;$server = ServerManager::getInstance()->getSwooleServer();$server->push($fd,json_encode($messageData));//获取当前链接的详细信息$info = $server->getClientInfo($fd);//获取全部websocket中的链接fd//全员在线消息通知$server = ServerManager::getInstance()->getSwooleServer();$start_fd = 0;while(true){ $conn_list = $server->getClientList( $start_fd, $this->limit ); if ($conn_list===false || count($conn_list) === 0 || empty($conn_list)) { break; } $start_fd = end($conn_list); foreach ($conn_list as $fd){ $info = $server->getClientInfo($fd); if ($info && $info["websocket_status"] === WEBSOCKET_STATUS_FRAME) { $server->push($fd, json_encode($this->pushMsg)); } }}
项目里主要使用的功能点已经讲解完毕了,剩下的等有时间再整理。
责任编辑:hnmd003
相关阅读
-
每日快看:WTT球星挑战赛果阿站:梁靖崑击败林诗栋获得男单冠军
北京时间5日晚,WTT球星挑战赛果阿站结束男单决赛的争夺,梁靖崑4:2(11:6 9:11 10:12 12:10 12:10 ...
2023-03-05 -
环球今亮点!WTT球星挑战赛果阿站:王艺迪摘得女单冠军
北京时间5日晚,WTT球星挑战赛果阿站结束女单决赛的争夺,王艺迪4:0(11:6 11:6 11:8 11:4)击败中国台...
2023-03-05 -
世界热议:两会快讯 |?生态环境部:推动经济社会绿色低碳转型从源头上根本改善
3月5日上午,十四届全国人大一次会议首场“部长通道”在人民大会堂举行,工信部部长金壮龙,科技部部长...
2023-03-05
阅读排行
资讯播报
- 全球滚动:WTT球星挑战赛果阿站:...
- 焦点信息:巴黎圣日耳曼4:2战胜南...
- 实现新的突破!冬运中心向国家青...
- 【新要闻】吉林:以丰富森林资源...
- 天天讯息:【星风羁旅】第二章 ...
- 热评两会丨“屏对屏”“面对面”...
- 伤愈归来!体操世界杯多哈站夺冠...
- CBA恢复主客场赛制 广州队重返...
- 全国竞走大奖赛传捷报 贺相红轻...
- WTA蒙特雷赛再传捷报 朱琳晋级...
- 全球滚动:去除甲醛最有效方法
- 每日视讯:加入3元水混战 今麦...
- 两会描绘发展蓝图备受期待
- 中国围棋西南棋王赛首日 柯洁唐...
- 【环球新视野】斯巴达首批冰雪勇...
- 焦点速递!“迎杭州亚运会趣味跑...
- 浙台青少年以棒垒球会友 汗水中...
- 重庆历史最悠久马拉松开跑 选手...
- 当前讯息:汽车行业热门岗位薪酬...
- 环球最新:强信心·开新局|记者...
- 镜观中国 | 雷锋精神,永不过时
- 世界动态:中国田径运动员贺相红...
- 视焦点讯!花山文化节
- 热点在线丨国际体联世界杯赛多哈...
- 环球今热点:响应共富分配8万套...
- 天天通讯!黄百韬简介
- 世界观热点:修改立法法贯彻体现...
- 备战亚洲杯亚运会 中国女篮出台...
- 当前消息!全国春耕春播工作由南...
- 世界观察:时隔三年重回主场 ...
- 天天微速讯:(两会声音)全国政...
- 联想笔记本触摸屏没反应怎么办_...
- 当前讯息:打报告格式及范文(共6篇)
- 环球看点!德约科维奇20连胜告破...
- 全球资讯:体操世界杯刘洋吊环夺...
- 保定定州市哪些情形可以提取住房...
- 全球聚焦:三夺世锦赛冠军 蔡雪...
- 【全球新视野】国足迅速进入技战...
- 世界头条:艾克森离开国家队 中...
- 天天热点评!中国女篮新一期集训...
- 恩艾中国成为长三角国创中心全球...
- 当前焦点!时代中国单月合同销售1...
- 当前消息!四川女篮实现20连胜 ...
- 开局加把劲丨好建议从一线来!新...
- 天天微头条丨机构:2月整体市场...
- 闽台青年人才体育交流营启动 ...
- 每日速递:上海海港新主帅哈维尔...
- 多孩家庭可购第3套房!多地优生...
- 【地评线】中安时评:共赴春天的...
- U20男足亚洲杯:中国队1:2不敌日本
- 环球看热讯:中国西昌·2022萨马...
- 莱茵体育股权转让纠纷案件裁决作...
- 热门:外媒:看好中国市场潜力 ...
- 全国政协十四届一次会议将安排开...
- 奋进的春天|深圳站春运后客流不...
- 全球讯息:中国女足球员走进凉山...
- 【天天速看料】中百集团:新光集...
- 龙湖启德尚·珒溋累售606单位 ...
- 新大正:正在积极推进7.88亿元收...
- 环球聚焦:深圳人才安居发行10亿...
- 全球微资讯!海南:将体育旅游产...
- 【环球速看料】2月产业园区好文...
- 当前动态:首旅酒店:发行超短期...
- 天天快播:大唐集团:2月合约销...
- 大唐集团控股:前2月合约销售额...
- 环球快播:西部建设3.11亿元收购...
- 大咖云集,共襄盛会山西省优生科...
- 田协公布世锦赛和亚运会选拔标准...
- 每日消息!速滑世锦赛:中国队女...
- 摩根士丹利料2月香港零售销货价...
- 选址面积合计逾1010亩 福州开年...
- 上海临港集团20亿元公司债将付息...
- 天天看热讯:中国国奥队集训名单...
- 【世界时快讯】“世界棋后”挑战...
- 天天百事通!蔡雪桐夺单板滑雪世...
- 当前观点:金生游乐IPO融资规模...
- 中国户外品牌伯希和速影PRO惊喜...
- 【新要闻】南京:拍地竞买保证金...
- 全球快资讯:央行副行长潘功胜:...
- 中航京能光伏REIT正式获证监会批...
- 全球快讯:易纲:今年将巩固实际...
- 环球视讯!快手与深圳中原合作:...
- 国货崛起,FLOSSOM花至科学抗老...
- 走进享梦游:社交旅行为什么深受...
- 当前热讯:2022世界杯的举办地在...
- 环球百事通!《唐人街探案2》票...
- 精选!你会射箭吗?射箭的比赛规...
- 巴西蜂胶的功效与作用是什么?巴...
- 全球时讯:郑州有哪些不错的游泳...
- 全球热讯:武汉女足主帅常卫魏:...
- 每日热文:电影Super8怎么样?如...
- 精选!扬科维奇率新一期中国男足...
- 用建行卡如何开通支付宝?建行卡...
- 天天速读:新能源汽车线束的耐热...
- 让体育与文化交相辉映
- 世界新动态:深圳发布数据交易新...
- 中国短道速滑队主教练张晶谈世锦...
- 环球报道:国足海口第一练以恢复为主
- INTO YOU心慕与你携手超模CIci...
- 全球即时看!特斯拉将放弃稀土材...