thinkphp5.0 使用GatewayWorker实现一对一聊天详解

17 篇文章 1 订阅

1.GatewayWorker下载地址:https://www.workerman.net/download
2.将下载的文件放置vendor目录(原理上服务器任何位置都可以)
3.将GatewayWorker/Applications/YourApp/start_gateway.php第24行

$gateway = new Gateway("tcp://0.0.0.0:8282");

修改为

$gateway = new Gateway("Websocket://0.0.0.0:8282");

开启心跳检测:
将38行和40行的注释去掉,即:

// 心跳间隔
$gateway->pingInterval = 10;
// 心跳数据
$gateway->pingData = '{"type":"ping"}';

开启后,在用户与服务器连接成功后,每十秒向客户端发送“ping“以保持长时间连接,否则服务器将断开服务器与客户端的链接
此方法为服务端主动发起,其还可以从客户端主动发起(之后补充)
4.开启服务
使用服务器宝塔终端或xshell等其他命令工具,进入GatewayWorker根目录
输入:php start.php start
输出系统所示信息表示socket服务启动成功
注:每次修改服务端代码,soceket都需要进行重启
在这里插入图片描述
5.修改GatewayWorker/Applications/YourApp/Events.php

public static function onConnect($client_id)
    {
            Gateway::sendToClient($client_id, json_encode([
                'type'=>'init',//客户连接后向用户发送绑定uid请求(1)
                'client_id'=>$client_id
              ]));
    }
    
   /**
    * 当客户端发来消息时触发
    * @param int $client_id 连接id
    * @param mixed $message 具体消息
    */
   public static function onMessage($client_id, $message)
   {
        $message_data = json_decode($message,true);
        if(!$message_data){
          return;
        }
        switch ($message_data['type']) {
          case "say":
            $content = $message_data['data'];
            $fromid = $message_data['fromid'];
            $toid = $message_data['toid'];
            $infotype = $message_data['infotype'];
            $data = [
              'type' => 'answer',
              'id' => $client_id,
              'fromid' =>$fromid,
              'toid' => $toid,
              'time' => time(),
              'data' => $content,
              'infotype' => $infotype
            ];
           
            if(Gateway::isUidOnline($toid)){//判断用户是否在线
              $data['isread'] = 1;
              Gateway::sendToUid($toid, json_encode($data));//向指定用户发送信息
            }else{
              $data['isread'] = 0;
              $data['type'] = 'save';
              Gateway::sendToUid($fromid,json_encode($data));//向指定用户发送信息
            }
          break;
          case "bind":
            /*接收到客户端发来的uid后进行绑定(3)*/
            $uid = $message_data['fromid'];
            Gateway::bindUid($client_id,$uid);//将client_id与uid进行绑定
          break;
          case "pong":
            return ;//心跳检测
          break;
        }
   }

6.在前端代码中添加以下js代码

<script type="text/javascript">
    var fromid = {$from_id};
    var toid = {$uid};
    var ws = new WebSocket("ws://0.0.0.0");
      ws.onmessage = function(e){
        console.log(e);
          var message = eval("("+e.data+")");
          switch(message.type){
              case "answer" :
                  if(toid==message.fromid){
                      var html = '';
                      if(message.infotype=='1'){
                        html += '<li class=\"right\">'+'<p>'+message.data+'</p>'+'</li>';
                      }else{
                        html += '<li class=\"right\"><img src=\"'+message.data+'\" style="width:100px;height:100px;"></li>';
                      }
                      
                      $("#talk").append(html);
                      message.type = '1';
                      send(message);
                  }
              break;
              case "init" :
                  var bind = '{"type":"bind","fromid":"'+fromid+'"}';
                  ws.send(bind);/*接收到服务端发来的绑定uid请求,将uid发送至服务端进行绑定(2)*/
              break;
              case "ping" :
                var pong = '{"type":"pong","fromid":"'+fromid+'"}' 
              break;
              case "save" :
                if(message.fromid==fromid){
                    message.fromid = toid;
                    message.type='2';
                    send(message);
                }
            break;
          }
      };
      $(".send-btn").click(function() {
          var message = $("#comment").val();
          var html = '';
          html += '<li class=\"left\">'+'<p>'+message+'</p>'+'</li>';
          $("#talk").append(html);
          $("#comment").val("");
          var msg = '{"type":"say","infotype":"1","data":"'+message+'","fromid":"'+fromid+'","toid":"'+toid+'"}';
          // send();
          ws.send(msg); 

      });
  function send(message){
    var uid = message.fromid;
    var content = message.data;
    var time = message.time;
    var isread = message.isread;

    $.ajax({
        url: "{:url('vilage/message/talk')}",
        type: 'POST',
        dataType: 'json',
        data: {
            'uid' : uid,
            'content' : content,
            'time' : time,
            'isread' : isread,
            'type':message.type,
            'info_type':message.infotype
        }
    })
  }
  
  $(document).ready(function(){
    $('#talk').scrollTop( $('#talk')[0].scrollHeight );
  });

  $("#pic").click(function() {
          $("#file").click();
  });
  $("#file").change(function() {
        fromdata = new FormData();
        fromdata.append('file',$("#file")[0].files[0]);
        $.ajax({
            url: "{:url('vilage/message/upload')}",
            type: 'post',
            dataType: 'json',
            data: fromdata,
            processData:false,
            contentType:false,
            success:function(res){
                console.log(res);
                res = JSON.parse(res);
                console.log(res);
                if(res.code==1)
                {
                    var domain = window.location.host;
                    var imgurl = 'http://' + domain + res.url;
                    var msg  = '{"type":"say","infotype":"2","infotype":"2","data":"'+imgurl+'","fromid":"'+fromid+'","toid":"'+toid+'"}';
                    var html = '';
                    html += '<li class=\"left\"><img src=\"'+imgurl+'\" style="width:100px;height:100px;"></li>';
                    $("#talk").append(html);
                    $(".chat-content").append(html);

                    ws.send(msg);
                }else{
                    alert(res.msg);
                }
            }
        })
        
    });
   
</script>

7.对应的html模板为:

<div class="panel panel-default panel-intro">
    <input type="hidden" id="uid" value="{$uid}">
    <div class="main wrap">
        <ul id="talk" class="wrap">
            {foreach name="list" item="vo"}
              {if condition="$vo.message_type!='2'"}
                  
                  {if condition="$vo.info_type=='1'"}
                      <li class="right"><p>{$vo.message_info}</p></li>
                  {else}
                      <li class="right"><img src="{$vo.message_info}" style="width:100px;height:100px;"></li>
                  {/if}
              {else}
                  {if condition="$vo.info_type=='1'"}
                      <li class="left"><p>{$vo.message_info}</p></li>
                  {else}
                      <li class="left"><img src="{$vo.message_info}" style="width:100px;height:100px;"></li>
                  {/if}
              {/if}
            {/foreach}
        </ul>
    </div>

    <div class="comment">
        <textarea id="comment" class="form-control editor" rows="1" name="comment" cols="50"></textarea>
        <input type="file" name="pic" id="file" style="display:none">
        <span id="pic">图片</span>
        <button type="button" class="butt send-btn">发送</button>
    </div>
</div>

以上就实现了消息和图片的实时通信,及消息持久化
8.思路:
a.用户打开链接后服务器发送绑定uid请求
b.客户端接收到服务器的绑定uid请求后,将用户id发送给服务端
c.服务端接收到uid后进行绑定
d.用户发送消息后将消息追加至消息列表,并发送给服务端
e.服务端判断to_user是否在线和消息的类型(文字或图片)
f.如果to_user在线即服务端发送给to_user,否则服务端发送给from_user让其进行存储
g.如果to_user在线,则其接受到消息后进行存储,并追加至消息列表

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值