PHP+Laravel5.8+GatewayWorker实现即时文字聊天,文件互传功能(第二篇:GatewayWorker基类的配置与部署)
- 第二篇:GatewayWorker基类的配置与部署
-
- php端部署
- 前往Workerman服务端开启socket服务。
- 前端H5页面编写
- 总结
-
- 客户端(H5页面)、workerman服务端、php服务端 三者之间的关系
第二篇:GatewayWorker基类的配置与部署
本章节将演示:
1.代码的在服务器的部署过程
2.前端是如何将消息发送给后台的并进行处理的。
php端部署
1.上一章节我讲过,这个项目分为3端(客户端、通信端、服务端),他们的设计思路我在这里再次明确一下。
客户端(前端H5页面):负责展示和发送用户之间往来的消息内容。
通信端:负责接受和发送用户的消息内容。
服务端:负责处理发送消息和接收消息的业务逻辑等(如用户的聊天记录存入数据库、用户消息的撤回、用户发送违规图片的审核等一些功能,我们都在这里完成)。
2.前面章节我们在workerman->GatewayWorker手册官网下载的Linux系统快速开始的Demo
现在我把他复制到项目中的根目录中来。目录如下图所示:
3.开始填写配置(在配置之前请开发者一定先阅读手册一下内容,这很重要,因为后面有些坑都在这里)GatewayWorker->开发必读
现在打开 项目名\GatewayWorker\Applications\YourApp\start_gateway.php
根据你的业务需求修改 设置Gateway的协议为websocket因为H5客户端要用这个协议进行通讯。
我的域名有https证书所以我修改了配置项,相关文档请参考官方手册GatewayWorker手册->创建wss服务
$gateway = new Gateway("websocket://0.0.0.0:8282",$context);//这里的8282端口就是上一章节提前在服务器安全组中放行的。这个‘websocket:’协议是H5用的,这里的配置必须和H5前端的配置一致// 服务注册地址
$gateway->registerAddress = '127.0.0.1:1238';//这个1238端口自己在服务器安全组中放行即可。代码里无需改动。
代码如下:
<?php
/*** This file is part of workerman.** Licensed under The MIT License* For full copyright and license information, please see the MIT-LICENSE.txt* Redistributions of files must retain the above copyright notice.** @author walkor<walkor@workerman.net>* @copyright walkor<walkor@workerman.net>* @link http://www.workerman.net/* @license http://www.opensource.org/licenses/mit-license.php MIT License*/
use \Workerman\Worker;
use \Workerman\WebServer;
use \GatewayWorker\Gateway;
use \GatewayWorker\BusinessWorker;
use \Workerman\Autoloader;// 自动加载类
require_once __DIR__ . '/../../vendor/autoload.php';// gateway 进程,这里使用Text协议,可以用telnet测试
/*** https用我*/
$context = array('ssl' => array('local_cert' => '/www/server/panel/vhost/cert/im_dev.liutong.pro/4539259_im.liutong.pro.pem', // 或者crt文件域名证书以及秘钥文件路径)'local_pk' => '/www/server/panel/vhost/cert/im_dev.liutong.pro/4539259_im.liutong.pro.key',//(域名证书以及秘钥文件路径)'verify_peer' => false)
);
$gateway = new Gateway("websocket://0.0.0.0:8282",$context);//https用这个
// 设置transport开启ssl,websocket+ssl即wss
$gateway->transport = 'ssl';//https用这个#****** https向上面一样配置 ******* 分割线 ****** http向下面$gatewayy一样配置 **************/*** http用我*/
//$gateway = new Gateway("websocket://0.0.0.0:8282");//http用这个// gateway名称,status方便查看
$gateway->name = 'YourAppGateway';
// gateway进程数
$gateway->count = 4;
// 本机ip,分布式部署时使用内网ip
$gateway->lanIp = '127.0.0.1';
// 内部通讯起始端口,假如$gateway->count=4,起始端口为4000
// 则一般会使用4000 4001 4002 4003 4个端口作为内部通讯端口
$gateway->startPort = 2900;
// 服务注册地址
$gateway->registerAddress = '127.0.0.1:1238';// 心跳间隔(单位:秒,注意这里服务端50s访问前端一次,前端50后返回后端一次,一来一回的时间应为 50s*2 = 100s)
$gateway->pingInterval = 50;
// 心跳数据(标识)
$gateway->pingData = '{"type":"ping"}';/* // 当客户端连接上来时,设置连接的onWebSocketConnect,即在websocket握手时的回调 $gateway->onConnect = function($connection) {$connection->onWebSocketConnect = function($connection , $http_header){// 可以在这里判断连接来源是否合法,不合法就关掉连接// $_SERVER['HTTP_ORIGIN']标识来自哪个站点的页面发起的websocket链接if($_SERVER['HTTP_ORIGIN'] != 'http://kedou.workerman.net'){$connection->close();}// onWebSocketConnect 里面$_GET $_SERVER是可用的// var_dump($_GET, $_SERVER);}; }; */// 如果不是在根目录启动,则运行runAll方法
if(!defined('GLOBAL_START'))
{
Worker::runAll();
}
自此你的workerman服务端就配置好了。但是现在还不能用,我们现在开始编写前端代码。
前往Workerman服务端开启socket服务。
1.登录你的阿里云服务器控制台,使用cd命令进入项目根目录中,然后进入GatewayWorker目录中找到start.php使用php命令php start.php start
回车看到下图表示服务成功,
参考手册地址:GatewayWorker手册->启动与停止
前端H5页面编写
1.laravel配置一个路由用来访问呢前端页面。
2.页面的内容我们可以直接从GatewayWorker官方手册->ThinkPHP等框架结合->网站页面js片段中提取
网站页面js片段
{
{
--即时通讯业务逻辑--}}
<script>/*** 第一步:与socket建立链接* 打开一个 web socket (以下链接方式任选一种即可)* 参数解释:var ws = new WebSocket("参数A://参数B:参数C");* 参数A:固定写法ws:表示http连接wss:表示https连接,有https证书的时候使用* 参数B:要连接的地址。可选参数:127.0.0.1 表示:本地地址可选参数:48.662.156.869 表示:你的云服务器的公网ip (48.662.156.869这个ip是我假设的云服务器公网ip)可选参数:im_dev.liutong.pro 表示:这个你的http域名 如(http://im_dev.liutong.pro)可选参数:im.liutong.pro 表示:这个是你的https网址域名 如(https://im.liutong.pro)* 参数C:端口号端口号是可以自定义的(注意取值范围)。记得在服务器->实例安全组中进行放行。端口号取值范围:端口不能大于65535,请确认端口没有被其它程序占用,否则启动会报错。如果端口小于1024,需要root权限运行GatewayWorker才能有权限监听,否则报错没有权限。(详情参见手册->《Gateway类的使用》->"初始化"->"ip")注意:这里的端口号必须和你在 "项目名\GatewayWorker\Applications\YourApp\start_gateway.php" 中$gateway = new Gateway("websocket://0.0.0.0:8282");这段代码的端口号保持一致。*/// var ws = new WebSocket("ws://127.0.0.1:8282");//进行webSocket的几种方式(方式A:常规操作)// var ws = new WebSocket("ws://47.104.249.193:8282");//进行webSocket的几种方式(方式B:使用本机公网ip进行连接)// var ws = new WebSocket("ws://im_dev.liutong.pro:8282");//进行webSocket的几种方式(方式C:使用http://im_dev.liutog.pro的方式进行连接)var ws = new WebSocket("wss://im.liutong.pro:8282");//进行webSocket的几种方式(方式D:使用HTTPS的方式进行连接,域名:https:im.liutong.pro)//第二步:webSocketn事件 open连接建立时触发ws.onopen = function() {
console.log("连接成功");};//第三步:webSocketn事件 onmessage客户端接收服务端数据时触发ws.onmessage = function(evt) {
//console.log(evt);//console.log(evt.data);var data = JSON.parse(evt.data);//接受到服务器给我返回的JSON数据并进行解析switch(data.type) {
//验证链接类型(这个类型中的init值是官方定义的,我们无需改动,后续我们还会自定义一些type值。)case 'init'://表示首次链接,GatewayWorker发现有页面发起连接时,将对应连接的client_id发给网站页面//进行我方用户id与client_id进行绑定操作,这里我使用ajax请求我方自定义控制器进行处理用户绑定操作bindingUser("{
{Auth::user()->id}}",data.client_id);break;case 'binding_success'://用户绑定(用于当前用户刷新页面时,对我方用户id进行重新绑定)console.log(data.msg + 'A');break;case 'content_success'://接受好友发来的用户消息content_success(data);break;case 'ping'://心跳检测ws.send(JSON.stringify({
'type':"pong"}));break;case 'files_success'://接收好友base64文件//console.log(data);restoreFile(data);break;default:console.log('绑定失败');}};ws.onclose = function(){
// 关闭 websocketalert("连接已关闭...");};/*** 绑定我方用户id方法* @param user_id 我方用户id(数据来自“加载页面控制器”传递进来)* @param client_id GatewayWorker发现有页面发起连接时,将对应连接的client_id发给网站页面,注意:此id是唯一的,每次重新链接都会发送一个新的client_id给我们* 我方用户id与client_id的关系为一对多,及我方id为一个,可对应多个client_id。* 通信时已我方用户id作为唯一标识!*/function bindingUser(user_id,client_id) {
$.ajax({
type : "POST", //提交方式url : "{
{route('im.bindingUser')}}",//路径data : {
'_token':'{
{csrf_token()}}'//laravel 防止ajax POST请求报419错误方法,'user_id' : user_id,'client_id' : client_id},//数据,这里使用的是Json格式进行传输success : function(result) {
//返回数据根据结果进行相应的处理var data = JSON.parse(result);//接受到服务器给我返回的JSON数据并进行解析if (data.success) {
// console.log('绑定结果:' + data.msg);} else {
alert('绑定失败22222');}}});}/*** 接收处理好友发来的数据* @param data*/function content_success(data) {
console.log(data);alert(1111);return false;let class_name = '.chat_ul_' + data.addresser_id;//设定需要显示的class名称let demo = "<li class=\"his_content chat\">\<n></n>" +" <span>"+ data.msg +"</span>\<n></n>" +" </li>";$(class_name).append(demo);}/*** 将base64文件进行还原展示* @param data*/function restoreFile(data){
console.log(data);switch (data.file_type) {
case 'mp3':let chat_id = 'left';//对方发送li classe名showSendFile(data.msg,data.file_type,data.file_id,data.audio_time,chat_id);break;case 'a'://自定义业务逻辑break;case 'b'://自定义业务逻辑break;case 'c'://自定义业务逻辑break;default:break}}/*** 发送文件到指定用户* @param base64_data base64格式的文件* @param type 指定的文件类型*/function sendFile_user(base64_data,file_type){
$.ajax({
url:"{
{route('im.sendFile_user')}}",type:"post",data: {
'base64_data': base64_data,//base64文件'file_type': file_type,//文件类型'_token': '{
{csrf_token()}}',//token过CSRF用的'recipients':"{
{$addressee['id']}}",//收件人id'audio_time':audio_time,//录音时长(全局变量)},dataType:"json",success:function(data){
if(data.success == true){
console.log(data);alert("上传成功");let audio_time_2 = data.audio_time;//录音时长let file_id = data.file_id;//文件唯一idlet chat_id = 'right';//我方发送li classe名showSendFile(base64_data,file_type,file_id,audio_time_2,chat_id);//显示发送的文件}else{
alert("上传失败");}},error:function(){
console.log("上传失败");}});}
</script>
注意:1.首先我没把我写的js全拿出来,报错说方法找不到的,可以根据我的注释自己写业务逻辑,或者直接把方法名删掉都可以。
重点:这里有好朋友回报:ws或者wss链接超时、无法连接错误。这可能是你的服务器防火墙引起的,直接关闭防火墙简单粗暴,问题直接解决绝。(但是这个解决方案不推荐,请自行优化解决。)
如果你关闭了服务器防火墙依然无法解决,请你仔细阅读官方手册《GatewayWorker手册->-开发必读》章节的上半章内容中的6条注意事项,耐心排查。
总结
客户端(H5页面)、workerman服务端、php服务端 三者之间的关系
1.通俗易懂的讲法:我们把这其中的关系想象成‘邮差送信服务’
客户端=发件人/收件人。
workerman服务端 = 邮差,负责跑腿的。
php服务端 = 邮局,给邮差安排任务的地方。
发件人A想要发消息,他先去邮局告诉邮局发件人A的基本身份信息,在告诉邮局要邮寄的东西是什么,需要邮寄给谁。
邮局收到了发件人A的诉求。开始安排邮差去送信
邮差根据发件人A提供的信息去收件人的地址执行送信业务。
他们所扮演的角色就是这样。