前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >easyswoole实现在线聊天室功能

easyswoole实现在线聊天室功能

作者头像
仙士可
发布2019-12-19 14:02:34
2K0
发布2019-12-19 14:02:34
举报

一 : 安装easyswoole,可参考https://cloud.tencent.com/developer/article/1556424

把example/example\multiUsage_01\的实例覆盖到src,访问ip:端口(9501)/test/websocket.php可查看最简单实例

灵活组合加上前端可以做的非常好

以下为我自己项目修改后的代码,看不懂可以去看简单实例

前台js

var user_info;
var is_connect = 0;
var websocket;
var msg = 0;
is_login();
autoWidth();
var initWebSocket = function () {
    var wsServer = 'ws://139.199.164.211:9501';
    websocket = new WebSocket(wsServer);
    websocket.onopen = function (evt) {
        var html = '<p>正在连接服务器...</p>';
        addLine(html);
    };
    websocket.onclose = function (evt) {
        var html = '<p>服务器异常关闭,正在重连</p>';
        addLine(html);
        socket_connect();
    };
    websocket.onmessage = function (evt) {
        var data = JSON.parse(evt.data);
        if (data['status'] == false) {
            msgTip(data['info']);
            return;
        }
        if (parseInt(data['fd']) > 0) {
            $.ajax({
                url: SiteUrl + 'index.php?g=Res&m=Chat&a=add_client',
                dataType: 'JSON',
                data: {fd: data['fd'], key: key},
                type: 'POST',
                success: function (res) {
                    check_login(res);
                    /*  if (res['status'] == false) {
                     msgTip(res['info']);
                     return;
                     }*/
                    is_connect = 1;
                    user_info = res['data'];
                    var html = '<p>连接服务器成功</p>';
                    addLine(html);
                }
            });
        } else {
            if (data['user_info']['id'] == user_info['id']) {
                addMyLine(data['msg']);
            } else {
                addOthLine(data['msg'],data['user_info']);
            }
        }

        if (msg == 0) {//消息为0则返回最近聊天记录的10条
            get_msg();
        }
        msg++;
        if (msg >= 50) {
            $('#speak_box').find('div').eq(-30).prevAll().remove();
            msg = 30;
        }
    };
    websocket.onerror = function (evt, e) {
        loadingShow(evt.data);
    };
};

initWebSocket();

var socket_connect = function () {
    window.connect = setInterval(function () {
        initWebSocket();
        if (is_connect == 1) {
            clearInterval(window.connect);
        }
    }, 5000);
};

function addLine(data) {
    var html = '<div class="answer">';
    html += data;
    html += '</div>';
    $('#speak_box').append(html);
}
function addMyLine(data) {
    var html = '<div class="question">';
    html += '<div class="heard_img right"><img src="' + Host + '/data/upload/avatar/' + user_info.avatar + '"></div>';
    html += '<div class="question_text clear" style="max-width: 285px;"><p>' + html2Escape(data) + '</p><i></i></div>';
    html += '</div>';
    $('#speak_box').append(html);
}
function addOthLine(msg,user) {
    if (user.avatar == null) {
        user.avatar = 'admin.gif';
    }
    var html = '<div class="answer">';
    html += '<div class="heard_img left"><p>' + user.user_nicename + '</p><img src="' + Host + '/data/upload/avatar/' + user.avatar + '"></div>';
    html += '<div class="answer_text" style="max-width: 285px;"><p>' + html2Escape(msg) + '</p><i></i></div>';
    html += '</div>';
    $('#speak_box').append(html);
}

function send(msg, to_user_id) {
    to_user_id = to_user_id ? to_user_id : 0;

    $.ajax({
        url: SiteUrl + 'index.php?g=Res&m=Chat&a=add_msg',
        dataType: 'JSON',
        data: {key: key, to_user_id: to_user_id, msg: msg},
        type: 'POST',
        success: function (res) {
            check_login(res);
            if (res['status'] == false) {
                msgTip(res['info']);
                return;
            }
            data = '{"msg":"' + msg + '","key":"' + key + '"}',
                websocket.send(data);
        }
    });
}

function get_msg() {
    $.ajax({
        url: SiteUrl + 'index.php?g=Res&m=Chat&a=get_msg',
        dataType: 'JSON',
        data: {key: key},
        type: 'POST',
        success: function (res) {
            check_login(res);
            if (res['status'] == false) {
                msgTip(res['info']);
                return;
            }
            for (var x in res['data']['list']){
                var vo = res['data']['list'][x];
                if (vo['user_id'] == user_info['id']) {
                    addMyLine(vo['content']);
                } else {
                    addOthLine(vo['content'],vo);
                }
            };
        }
    });
}


var wen = document.getElementById('wenwen');
function _touch_start(event) {
    event.preventDefault();
    $('.wenwen_text').css('background', '#c1c1c1');
    $('.wenwen_text span').css('color', '#fff');
    $('.saying').show();
}

function _touch_end(event) {
    event.preventDefault();
    $('.wenwen_text').css('background', '#fff');
    $('.wenwen_text .circle-button').css('color', '#666');
    $('.saying').hide();
    var str = '<div class="question">';
    str += '<div class="heard_img right"><img src="../assets/images/chat/dglvyou.jpg"/></div>';
    str += '<div class="question_text clear"><p>不好意思,我听不清!</p><i></i>';
    str += '</div></div>';
    $('.speak_box').append(str);
    for_bottom();
    setTimeout(function () {
        var ans = '<div class="answer"><div class="heard_img left"><img src="../assets/images/chat/dglvyou.jpg"/></div>';
        ans += '<div class="answer_text"><p>我不知道你在说什么?</p><i></i>';
        ans += '</div></div>';
        $('.speak_box').append(ans);
        for_bottom();
    }, 1000);
}

wen.addEventListener("touchstart", _touch_start, false);
wen.addEventListener("touchend", _touch_end, false);

function for_bottom() {
    var speak_height = $('.speak_box').height();
    $('.speak_box,.speak_window').animate({scrollTop: speak_height}, 500);
}

function autoWidth() {
    $('.question_text').css('max-width', $('.question').width() - 60);
}

function to_write() {
    $('.wenwen_btn img').attr('src', '../assets/images/chat/yy_btn.png');
    $('.wenwen_btn').attr('onclick', 'to_say()');
    $('.write_box,.wenwen_help button').show();
    $('.circle-button,.wenwen_help a').hide();
    $('.write_box input').focus();
    for_bottom();
}

function to_say() {
    msgTip('暂不支持语音聊天');
    return;
    $('.write_list').remove();
    $('.wenwen_btn img').attr('src', '../assets/images/chat/jp_btn.png');
    $('.wenwen_btn').attr('onclick', 'to_write()');
    $('.write_box,.wenwen_help button').hide();
    $('.circle-button,.wenwen_help a').show();
}


function keyup() {
    var footer_height = $('.wenwen-footer').outerHeight(),
        text = html2Escape($('.write_box input').val()),
        str = '<div class="write_list">' + html2Escape(text) + '</div>';
    if (text == '' || text == undefined) {
        $('.write_list').remove();
    } else {
        $('.write_list').remove();
        $('.wenwen-footer').append(str);
        $('.write_list').css('bottom', footer_height);
    }
}

function up_say() {
    $('.write_list').remove();
    var text = $('.write_box input').val();
    if (text.length < 1) {
        msgTip('内容不能为空');
        return;
    }
    $('.write_box input').val('');
    $('.write_box input').focus();
    autoWidth();
    for_bottom();
    send(text);
    /*
     setTimeout(function () {
     var ans = '<div class="answer"><div class="heard_img left"><img src="../assets/images/dglvyou.jpg"/></div>';
     ans += '<div class="answer_text"><p>您发送的文字是:' + text + '</p><i></i>';
     ans += '</div></div>';
     $('.speak_box').append(ans);
     for_bottom();
     }, 1000);*/
}

function removeHtmlTab(tab) {
    return tab.replace(/<[^<>]+?>/g, '');//删除所有HTML标签
}

function html2Escape(sHtml) {
    return sHtml.replace(/[<>&"]/g, function (c) {
        return {'<': '&lt;', '>': '&gt;', '&': '&amp;', '"': '&quot;'}[c];
    });
}

后台event.php监听文件

<?php
/**
 * Created by PhpStorm.
 * User: yf
 * Date: 2017/1/23
 * Time: 上午12:06
 */

namespace Conf;


use App\Model\Chat\Chat;
use Core\AbstractInterface\AbstractEvent;
use Core\AutoLoader;
use Core\Component\Di;
use Core\Component\Logger;
use Core\Component\Version\Control;
use Core\Http\Request;
use Core\Http\Response;
use Core\Swoole\SwooleHttpServer;
use Core\Swoole\Timer;
use App\Utility\Mysql;

class Event extends AbstractEvent
{
    function frameInitialize()
    {
        // TODO: Implement frameInitialize() method.
        date_default_timezone_set('Asia/Shanghai');
        $loader = AutoLoader::getInstance();
        $loader->requireFile("App/Vendor/MysqliDb/MysqliDb.php");
        $loader->requireFile("App/Vendor/Smarty/Smarty.class.php");
    }

    function beforeWorkerStart(\swoole_http_server $server)
    {
        // TODO: Implement beforeWorkerStart() method.
        //udp 请勿用receive事件
        //添加自带多协议监听
        $udp = $server->addlistener("0.0.0.0", 9502, SWOOLE_SOCK_UDP);
        $udp->on('packet', function (\swoole_server $server, $data, $addr) {
            Logger::console("receive data {$data}");
            $server->sendto($addr['address'], $addr['port'], "Swoole: $data");
        });

//        $listener = $server->addlistener("0.0.0.0",9502,SWOOLE_TCP);
//        //混合监听tcp时    要重新设置包解析规则  才不会被HTTP覆盖,且端口不能与HTTP SERVER一致 HTTP本身就是TCP
//        $listener->set(array(
//            "open_eof_check"=>false,
//            "package_max_length"=>2048,
//        ));
//        $listener->on("connect",function(\swoole_server $server,$fd){
//            Logger::console("client connect");
//        });
//        $listener->on("receive",function(\swoole_server $server,$fd,$from_id,$data){
//            Logger::console("received connect");
//            $server->send($fd,"swoole ".$data);
//            $server->close($fd);
//        });
//        $listener->on("close",function (\swoole_server $server,$fd){
//            Logger::console("client close");
//        });
        $server->on("handshake", function (\swoole_http_request $request, \swoole_http_response $response) {
            Logger::console("handshake");
            //自定定握手规则,没有设置则用系统内置的(只支持version:13的)
            if (!isset($request->header['sec-websocket-key'])) {
                //'Bad protocol implementation: it is not RFC6455.'
                $response->end();
                return false;
            }
            if (0 === preg_match('#^[+/0-9A-Za-z]{21}[AQgw]==$#', $request->header['sec-websocket-key'])
                || 16 !== strlen(base64_decode($request->header['sec-websocket-key']))
            ) {
                //Header Sec-WebSocket-Key is illegal;
                $response->end();
                return false;
            }

            $key = base64_encode(sha1($request->header['sec-websocket-key']
                . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',
                true));
            $headers = array(
                'Upgrade' => 'websocket',
                'Connection' => 'Upgrade',
                'Sec-WebSocket-Accept' => $key,
                'Sec-WebSocket-Version' => '13',
                'KeepAlive' => 'off',
            );
            foreach ($headers as $key => $val) {
                $response->header($key, $val);
            }
            $response->status(101);
            $response->end();
            $result['status'] = true;
            $result['fd'] = $request->fd;
            SwooleHttpServer::getInstance()->getServer()->push($request->fd, json_encode($result));
        });

        //添加websocket回调事件
        $server->on("message", function (\swoole_websocket_server $server, \swoole_websocket_frame $frame) {
            Logger::console("接收数据:" . $frame->data);
            $data = json_decode($frame->data, 1);
            $chat_model = new Chat();
            //验证用户
            $user_info = $chat_model->get_info('select id,
    user_login,
    user_nicename,
    user_email,
    avatar,
    coin,
    mobile,
    money,
    freeze_money,
    sex
     from dm_users WHERE login_key="' . $data['key'] . '" limit 1');
     //这段的sql代码参考\example\multiUsage_01\App\Model\Goods\goods.php 的Mysql基类 方法
            if (!$user_info) {
                $result = array();
                $result['status'] = false;
                $result['info'] = '你没有登陆账号!';
                $server->push($frame->fd, json_encode($result));
            } else {
                if(empty($user_info['avatar'])){
                    $user_info['avatar']='admin.gif';
                }
                $data['user_info'] = $user_info;
                unset($data['key']);
                $data['status']=true;
                $data['msg'] = htmlentities($data['msg']);
                foreach ($server->connections as $key => $value) {
                    $server->push($value, json_encode($data));
                }
            }
        });

        $server->on("close", function (\swoole_http_server $server, $fd) {
            $info = SwooleHttpServer::getInstance()->getServer()->connection_info($fd);
            if ($info['websocket_status']) {
                Logger::console("websocket 客户端 {$fd} 关闭");
            }
        });
        //添加websocket回调事件结束


    }

    function onStart(\swoole_http_server $server)
    {
        // TODO: Implement onStart() method.
        //使用event loop实现自定义 socket监听
        $listener = stream_socket_server(
            "udp://0.0.0.0:9503",
            $error,
            $errMsg,
            STREAM_SERVER_BIND
        );
        if ($errMsg) {
            throw new \Exception("listen fail");
        } else {
            //加入event loop
            swoole_event_add($listener, function ($listener) {
                $data = stream_socket_recvfrom($listener, 9503, 0, $client);
                Logger::console("rec data {$data} in event loop");
                stream_socket_sendto($listener, "hello this is event loop", 0, $client);
            });
        }
    }

    function onShutdown(\swoole_http_server $server)
    {
        // TODO: Implement onShutdown() method.
    }

    function onWorkerStart(\swoole_server $server, $workerId)
    {
        // TODO: Implement onWorkerStart() method.
        //为第一个worker添加一个定时器
        /*   if ($workerId == 0) {
               //10秒
               Timer::loop(10 * 1000, function () {
                   Logger::console("this is timer");
               });
           }*/

    }

    function onWorkerStop(\swoole_server $server, $workerId)
    {
        // TODO: Implement onWorkerStop() method.
    }

    function onRequest(Request $request, Response $response)
    {
        // TODO: Implement onRequest() method.
    }

    function onDispatcher(Request $request, Response $response, $targetControllerClass, $targetAction)
    {
        // TODO: Implement onDispatcher() method.
    }

    function onResponse(Request $request, Response $response)
    {
        // TODO: Implement afterResponse() method.
    }

    function onTask(\swoole_http_server $server, $taskId, $fromId, $taskObj)
    {
        // TODO: Implement onTask() method.
    }

    function onFinish(\swoole_http_server $server, $taskId, $fromId, $taskObj)
    {
        // TODO: Implement onFinish() method.
    }

    function onWorkerError(\swoole_http_server $server, $worker_id, $worker_pid, $exit_code)
    {
        // TODO: Implement onWorkerError() method.
    }
}

注意:easyswoole只能在php-cli状态下运行,你修改完代码需要重启服务才能使代码生效,详细操作方法请看server.php

注意:该文章写的example文件夹已经转移到官网的实例文档中,源码已经删除

关于数据库操作的文件也已经移除,需要自己去实现model层的操作,可以查找相关的操作类

本文为仙士可原创文章,转载无需和我联系,但请注明来自仙士可博客www.php20.cn

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-08-15 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档