websocket 封装类
后端PHP代码
<?php
class MySQLPool {
    private $serv = '';
    private $mysql = '';
    private $teacher_openid = 'oKMfe1QTsNbzpqslEr-U1b7q8rMQ'; // 老师的微信位移标识
    private $teacher_fd = ''; // 老师的文件描述符
    public function __construct() {
        // 创建socket套接字
        $this->serv = new \swoole_websocket_server("0.0.0.0", 9502);
        $this->serv->set(array(
            'worker_num' => 1, //worker进程数量
            'task_worker_num' => 1, //task进程数量 即为维持的MySQL连接的数量
            'reactor_num'=>8,
            'dispatch_mode' => 2,
            'debug_mode'=> 1,
            'daemonize' => 0, // 大于等于1 进程后台运行
            // 'log_file' => __DIR__.'/log/webs_swoole.log',
            'heartbeat_check_interval' => 60, // 表示每60秒,遍历所有连接,如果该连接在60秒内,没有向服务器发送任何数据,此连接将被强制关闭。
            'heartbeat_idle_time' => 600,
        ));
        // 绑定监听函数
        $this->serv->on('WorkerStart', array($this, 'onWorkerStart'));
        $this->serv->on('Open', array($this, 'onOpen'));
        $this->serv->on('Connect', array($this, 'onConnect'));
        $this->serv->on('Receive', array($this, 'onReceive'));
        $this->serv->on('Message', array($this, 'onMessage'));
        $this->serv->on('Close', array($this, 'onClose'));
        // bind callback
        $this->serv->on('Task', array($this, 'onTask'));
        $this->serv->on('Finish', array($this, 'onFinish'));
        $this->serv->start();
    }
    // MySQL链接数据库
    public function conn_mysql(){
        $mysql = new Swoole\Coroutine\MySQL();
        $res = $mysql->connect([
            'host' => '127.0.0.1',
            'user' => 'root',
            'password' => 'Bszpassword888',
            'database' => 'bsz',
        ]);
        #3
        if ($res == false) {
            echo("MySQL connect fail!");
            return;
        }
        $this->mysql = $mysql;
        return $mysql;
    }
    // 数据库插入操作
    public function my_insert($tbName, $data){
        $sql = "insert into ".$tbName."(".implode(',',array_keys($data)).") values(".implode(',',array_values($data)).")";
        echo PHP_EOL;
        echo $sql;
        echo PHP_EOL;
        
        return $this->mysql->query($sql);
    }
    public function onWorkerStart( $serv , $worker_id) {
        echo "workerstart: ".$worker_id.PHP_EOL;
        
}
    // 用户连接服务器响应函数
    public function onOpen($serv, $data){
        
        print_r($data->fd);
        echo PHP_EOL;
        // 获取老师fd
        if($this->teacher_openid == $data->get['openid']){
            $this->teacher_fd = $data->fd;
            // echo '我是老师: ' . $this->teacher_fd;
        }
        $mysql = $this->conn_mysql();
        $chat_date = date('Y-m-d', time());
        $sql = "select * from bsz_chat_room where create_time >= $chat_date";
        $messages = $mysql->query($sql);
        // print_r($messages);
        $mysql->close();
        // 获取历史聊天消息记录
        if(!empty($messages)){
            $m_data = [];
            $m_data['type'] = 'history_msg';
            $m_data['fd'] = $data->fd;
            $m_data['messages'] = $messages;
            // $serv->task($m_data);
        }
}
    public function onConnect( $serv, $fd, $from_id ) {
        echo "client:$fd Connect.".PHP_EOL;
    }
    public function onReceive( swoole_server $serv, $fd, $from_id, $data ) {
        echo "receive#{$from_id}: receive $data ".PHP_EOL;
    }
    // 用户发送消息响应函数
    public function onMessage($serv, $frame) {
        echo "message: ".$frame->data.PHP_EOL;
        $data = json_decode($frame->data, true);
        if($data['type'] == 'heart'){ //用户发送心跳包
            // 什么也不干,只是证明此用户还在聊天室, 保持长连接不中断
        }else if($data['type'] == 'speak'){ // 用户发送消息
            $create_time = date('Y-m-d H:i:s', time());
            $msg_id = date('Ymdhis') . str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT);
            // 判断消息发送者身份
            if($data['msg']['openid'] == $this->teacher_openid){
                $identity = '1';
                $origin_identity = '1';
            }else{
                $identity = '2';
                $origin_identity = '2';
            }
            
            $sql = "INSERT INTO `bsz`.`bsz_chat_room` (`openid`, `nickname`, `headimgurl`, `speak`, `identity`, `origin_identity`, `create_time`, `msg_id`) VALUES ('" . $data['msg']['openid']."', '". $data['msg']['nickname'] ."', '". $data['msg']['headimgurl'] ."', '". $data['msg']['speak'] ."', '$identity', '$origin_identity', '" . $create_time . "','". $msg_id ."')";
            $mysql = $this->conn_mysql();
            $ret = $mysql->query($sql);
            echo("swoole response is ok, result=".var_export($ret, true));
            // 关闭mysql连接,释放出连接数资源
            $mysql->close();
            $data['fd'] = $frame->fd;
            $data['msg_id'] = $msg_id;
            $data['teacher_openid'] = $this->teacher_openid;
            $data['teacher_fd'] = $this->teacher_fd;
            $data['identity'] = $identity;
            $data['origin_identity'] = $origin_identity;
            $serv->task($data);
            
        }else if($data['type'] == 'replay'){ // 老师回复用户消息
            $msg_id = $data['msg']['msg_id'];
            $sql = "select * from `bsz_chat_room` where msg_id='$msg_id' ";
            $mysql = $this->conn_mysql();
            $msg = $mysql->query($sql);
            // 关闭mysql连接,释放出连接数资源
            $mysql->close();
            $msg[0]['type'] = 'replay';
            $data['msg_id'] = $msg[0]['msg_id'];
            $data['msg'] = $msg[0]['msg'];
            $data['openid'] = $msg[0]['openid'];
            $data['nickname'] = $msg[0]['nickname'];
            $data['headimgurl'] = $msg[0]['headimgurl'];
            $serv->task($data);
        }
}
    public function onClose( $serv, $fd, $from_id ) {
        echo "Client {$fd} close connection\n";
        // $mysql = new Swoole\Coroutine\MySQL();
        // print_r($mysql);
    }
    public function onTask($serv,$task_id,$from_id, $data) {
        $msgArr = [];
        $msgStr = '';
        switch ($data['type']){
            case 'login':
                $msgArr['msg'] = '我来了~';
                $msgArr['nickname'] = $data['msg']['nickname'];
                $msgArr['headimgurl'] = $data['msg']['headimgurl'];
                $msgArr['user'] = 'login';
                $msgStr = json_encode($msgArr);
                // $send_msg = $msgStr;
                break;
            case 'history_msg': 
                foreach ($data['messages'] as $key => $value) {
                    $msgArr['msg'] = $value['speak'];
                    $msgArr['nickname'] = $value['nickname'];
                    $msgArr['headimgurl'] = $value['headimgurl'];
                    $msgArr['user'] = 'teacher';
                    $msgStr = json_encode($msgArr);
                    $serv->push($data['fd'], $msgStr);
                }
                
                break;
            case 'speak': 
                $msgArr['msg_id'] = $data['msg_id'];
                $msgArr['msg'] = $data['msg']['speak'];
                // $msgArr['openid'] = $data['msg']['openid'];
                $msgArr['nickname'] = $data['msg']['nickname'];
                $msgArr['headimgurl'] = $data['msg']['headimgurl'];
                if($data['origin_identity'] == '1'){ // 老师发送的消息
                    $msgArr['user'] = 'teacher';
                }else if($data['origin_identity'] == '2'){ // 粉丝发送的消息
                    $msgArr['user'] = 'fans';
                }
                // 老师发送的消息需要发送给所有人, 自己除外
                if($data['teacher_openid'] == $data['teacher_openid']){ 
                    $msgStr = json_encode($msgArr);
                    foreach ($serv->connections as $conn){
                        if($conn != $data['fd']){ // 不推送消息给自己
                            $serv->push($conn, $msgStr);
                        }
                    }
                }else{ // 其他人发送的消息,只需要转发给老师
                    // 添加粉丝发送消息标志
                    $msgStr = json_encode($msgArr);
                    $serv->push($data['teacher_fd'], $msgStr);
                }
break;
            case 'replay':
                $msgArr['user'] = 'replay';
                $msgArr['msg_id'] = $data['msg_id'];
                $msgArr['msg'] = $data['speak'];
                $msgArr['openid'] = $data['openid'];
                $msgArr['nickname'] = $data['nickname'];
                $msgArr['headimgurl'] = $data['headimgurl'];
                $msgStr = json_encode($msgArr);
                foreach ($serv->connections as $conn){
                    if($conn != $this->teacher_fd){ // 回复的消息不用再次推送给老师
                        $serv->push($conn, $msgStr);
                    }
                    
                }
break;
            default:
                break;
        }
        return;
    }
    public function onFinish($serv,$task_id, $data) {
        return true;
    }
}
new MySQLPool();
前端代码
<script type="text/javascript">
 // 一进来就滚动到底部
// $("#container").scrollTop($("#container")[0].scrollHeight);
// $("#btnSubmit").click(function(){
// 	//如果没有内容就return
// 	var txtVal=$("#msgInput").val();
//     // alert(txtVal);
//     if(txtVal==''){
//        return false;
//     }
// 	//有内容继续
// 	$('#msgList').append('<li>'+txtVal+'</li>');
//     $("#container").scrollTop($("#container")[0].scrollHeight);
// })
    // 用户基本信息(头像,昵称)
    var openid = "<?php echo $userinfo['openid'] ?>";
    var nickname = "<?php echo $userinfo['nickname'] ?>";
    var headimgurl = "<?php echo $userinfo['headimgurl'] ?>";
    // https://bszedu.com/static/public/images/qq.png
    // websocket连接地址
    // var wsUri ="wss://127.0.0.1:9502/"; 
    var wsUri ="wss://bszedu.com/websocket?openid=" + openid; 
    // JS初始化函数
    function init() { 
        // 三次握手连接服务器
        websocket = new WebSocket(wsUri); 
        websocket.onopen = function(evt) { 
            onOpen(evt) 
        }; 
        // 用户断开连接
        websocket.onclose = function(evt) { 
            onClose(evt) 
        }; 
        // 客户端接收到服务器消息
        websocket.onmessage = function(evt) { 
            onMessage(evt) 
        }; 
        // socket长连接出错
        websocket.onerror = function(evt) { 
            onError(evt) 
        };
    }
    // 获取用户需要发送的消息
    function get_speak_msg(){
        // var name = $("#name").val();
        // var nickname = nickname;
        var speak = $("#content").val();
        var arr_msg = {"nickname":nickname, "speak":speak, "headimgurl":headimgurl, 'openid':openid};
        return JSON.stringify(arr_msg);
    }
    // 打包用户消息 JSON格式
    function pack_msg(type, msg){
        return '{"type":"'+type+'","msg":'+msg+'}';
        // var arr_msg = {"type":type, "msg":msg};
        // return JSON.stringify(arr_msg);
    }
    // 客户端连接服务器
    function onOpen(evt) {
        var msgStr = '{"msg":"欢迎来到聊天室.........", "user":"welcome", "nickname":"' + nickname +'", "headimgurl":"' + headimgurl + '"}';
        // var a = JSON.stringify(arr_msg);
        append_speak(msgStr);
        // append_speak("已经联通服务器.........");
        // speak_msg = get_speak_msg();
        // send_msg = pack_msg("login", speak_msg);
        // doSend(send_msg);
    }
    function onClose(evt) { 
        var msgStr = '{"msg":"连接已断开!", "who":"me", "nickname":"' + nickname +'", "headimgurl":"' + headimgurl + '"}';
        append_speak(msgStr);
        // append_speak("俺老孙去也!");
    } 
    function onMessage(evt) {
        append_speak(evt.data);
    }
    function onError(evt) {
        alert(evt.data);
    }
    function doSend(message) { 
        websocket.send(message);
    }
  
    function append_speak(msgStr){
        var data = JSON.parse(msgStr); //由JSON字符串转换为JSON对象
        // 获取当前时间
        var myDate = new Date();
        var msg_hour = myDate.getHours();
        var msg_minute = myDate.getMinutes();
        msg_hour = msg_hour<10 ? '0'+msg_hour:msg_hour;
        msg_minute = msg_minute<10 ? '0'+msg_minute:msg_minute;
        var chat_time = msg_hour + ':' + msg_minute;
        // 老师的消息
        if(data['user'] == 'teacher'){
            var msg = '<li class="live-con-lis">' + 
                            '<img src="' + data.headimgurl + '" alt="" class="live-con-img">' +
                            '<div class="live-con-name">' +
                                '<p><span class="live-con-user">' + data.nickname + '</span><span class="live-con-time">'+ chat_time +'</span></p>' +
                                '<span class="live-con-text">' + data.msg + '</span>' + 
                                // '<a href="#" class="reply">回复用户></a>' +
                                // '<a href="javascript:;" class="reply" onclick="replay_client(this);" data-msg-id="'+ data.msg_id +'">回复用户></a>' + 
                            '</div>' + 
                        '</li>';
                // 添加消息到聊天窗
	        $('#chat-msg-ul').append(msg);
	        // 消息滚动到底部
	        $(".live-con").scrollTop($(".live-con")[0].scrollHeight);
        }else if(data['user'] == 'fans'){ // 粉丝的消息
            var msg = '<li class="live-reviewer">' + 
                            '<div class="live-reviewer-name">' + 
                                '<p style="text-align: right"><span class="live-reviewer-user">'+ data.nickname+'</span><span class="live-reviewer-time">'+ chat_time +'</span></p>' + 
                                '<div class="live-reviewer-text">' +
                                    '<span class="live-reviewer-ask">'+ data.msg +'</span>' + 
                                    '<a href="javascript:;" class="reply" onclick="replay_client(this);" data-msg-id="'+ data.msg_id +'">回复用户></a>' + 
                                '</div>' + 
                            '</div>' + 
                            '<img src="'+ data.headimgurl +'" alt="" class="live-reviewer-img">' + 
                        '</li>';
            // 添加消息到聊天窗
	        $('#chat-msg-ul').append(msg);
	        // 消息滚动到底部
	        $(".live-con").scrollTop($(".live-con")[0].scrollHeight);
        }else if(data['user'] == 'reply'){ // 用户成功连接服务器提示
        	// 判断老师 和 信息发送者的  openID
        	if(openid != data['openid']){ // 老师回复的消息,不用再次显示在自己屏幕
        		var msg = '<li class="live-reviewer">' + 
                            '<div class="live-reviewer-name">' + 
                                '<p style="text-align: right"><span class="live-reviewer-user">'+ data.nickname+'</span><span class="live-reviewer-time">'+ chat_time +'</span></p>' + 
                                '<div class="live-reviewer-text">' +
                                    '<span class="live-reviewer-ask">'+ data.msg +'</span>' + 
                                    // '<a href="javascript:;" class="reply" onclick="replay_client(this);" data-msg-id="'+ data.msg_id +'">回复用户></a>' + 
                                '</div>' + 
                            '</div>' + 
                            '<img src="'+ data.headimgurl +'" alt="" class="live-reviewer-img">' + 
                        '</li>';
	            // 添加消息到聊天窗
		        $('#chat-msg-ul').append(msg);
		        // 消息滚动到底部
		        $(".live-con").scrollTop($(".live-con")[0].scrollHeight);
        	}
            
        }else if(data['user'] == 'welcome'){
            var msg = '<li class="live-reviewer">' + 
                            '<div class="live-reviewer-name">' + 
                                '<p style="text-align: right"><span class="live-reviewer-user">'+ data.nickname+'</span><span class="live-reviewer-time">'+ chat_time +'</span></p>' + 
                                '<div class="live-reviewer-text">' +
                                    '<span class="live-reviewer-ask">'+ data.msg +'</span>' + 
                                '</div>' + 
                            '</div>' + 
                            '<img src="'+ data.headimgurl +'" alt="" class="live-reviewer-img">' + 
                        '</li>';
                // 添加消息到聊天窗
	        $('#chat-msg-ul').append(msg);
	        // 消息滚动到底部
	        $(".live-con").scrollTop($(".live-con")[0].scrollHeight);
}
        // document.getElementById("message").value=$("#message").val()+new_msg+"\n";
        // document.getElementById('message').scrollTop = document.getElementById('message').scrollHeight;
    }
    // 老师回复用户消息
    function replay_client(obj){
    	var msg_id = $(obj).attr('data-msg-id');
    	alert(msg_id);
    	var arr_msg = {"msg_id":msg_id};
        arr_msg = JSON.stringify(arr_msg);
        send_msg = pack_msg("replay", arr_msg);
        doSend(send_msg);
    	// alert(msg_id);
    	// console.log(msg_id);
    }
    function speak_to_all(){
        // 获取当前时间
        var myDate = new Date();
        var msg_hour = myDate.getHours();
        var msg_minute = myDate.getMinutes();
        msg_hour = msg_hour<10 ? '0'+msg_hour:msg_hour;
        msg_minute = msg_minute<10 ? '0'+msg_minute:msg_minute;
        var chat_time = msg_hour + ':' + msg_minute;
        // 获取消息输入框内容后, 清空消息输入框
        // var msg_con = $("#content").val();
        //如果没有内容就return
		var msg_con = $("#content").val();
	    // alert(txtVal);
	    if(msg_con==''){
	       return false;
	    }
        $("#content").val() == ""
        // 显示自己说的话到聊天窗
        if(openid == 'oKMfe1QTsNbzpqslEr-U1b7q8rMQ'){
        	var msg = '<li class="live-con-lis">' + 
                            '<img src="' + headimgurl + '" alt="" class="live-con-img">' +
                            '<div class="live-con-name">' +
                                '<p><span class="live-con-user">' + nickname + '</span><span class="live-con-time">'+ chat_time +'</span></p>' +
                                '<span class="live-con-text">' + msg_con + '</span>' + 
                                // '<a href="#" class="reply">回复用户></a>' +
                            '</div>' + 
                        '</li>';
        }else{
        	var msg = '<li class="live-reviewer">' + 
                        '<div class="live-reviewer-name">' + 
                            '<p style="text-align: right"><span class="live-reviewer-user">'+ nickname+'</span><span class="live-reviewer-time">' + chat_time + '</span></p>' + 
                            '<div class="live-reviewer-text">' +
                                '<span class="live-reviewer-ask">'+ msg_con +'</span>' + 
                                // '<a href="#" class="reply">回复用户></a>' + 
                            '</div>' + 
                        '</div>' + 
                        '<img src="'+ headimgurl +'" alt="" class="live-reviewer-img">' + 
                    '</li>';
        }
        
                    
        // 添加消息到聊天窗
        $('#chat-msg-ul').append(msg);
        // 消息滚动到底部
        $("#live-con").scrollTop($("#live-con")[0].scrollHeight);
        // 打包消息发送到服务器
        var send_msg = pack_msg("speak", get_speak_msg());
        doSend(send_msg);
    }
init();
    // 定时发送心跳包
    //循环执行,每隔1秒钟执行一次 1000 
    var my_heart=window.setInterval(heartbeat, 50000);
    function heartbeat() {
        // console.log("ready");
        // 打包消息发送到服务器
        var send_msg = pack_msg("heart", get_speak_msg());
        doSend(send_msg);
    }
    //去掉定时器的方法  
    // window.clearInterval(my_heart);
</script>
案例demo
<?php
// 创建socket套接字
$serv = new swoole_websocket_server("0.0.0.0", 9502);
//服务的基本设置
$serv->set(array(
    'worker_num' => 5, //worker进程数量
    'task_worker_num' => 5, //task进程数量 即为维持的MySQL连接的数量
    'reactor_num'=>8,
    'dispatch_mode' => 2,
    'debug_mode'=> 1,
    'daemonize' => 1, // 大于等于1 进程后台运行
    'log_file' => __DIR__.'/log/'. date('Y-m-d', time()) .'.webs_swoole.log',
    'heartbeat_check_interval' => 60, // 表示每60秒,遍历所有连接,如果该连接在60秒内,没有向服务器发送任何数据,此连接将被强制关闭。
    'heartbeat_idle_time' => 600,
));
$serv->on('connect', function ($serv,$fd){
	// echo "client:$fd Connect.".PHP_EOL;
});
//测试receive
$serv->on("receive",function(swoole_server $serv,$fd,$from_id,$data){
	// echo "receive#{$from_id}: receive $data ".PHP_EOL;
});
$serv->on('open', function($server, $req) {
	// echo "server#{$server->worker_pid}: handshake success with fd#{$req->fd}".PHP_EOL;;
	// echo PHP_EOL;
});
$serv->on('message',function($server,$frame) {
	// echo "message: ".$frame->data.PHP_EOL;
    $msg=json_decode($frame->data,true);
    switch ($msg['type']){
        case 'login':
            $server->push($frame->fd,"欢迎欢迎~");
            break;
        default:
            break;
    }
    $msg['fd']=$frame->fd;
    $server->task($msg);
});
$serv->on("workerstart",function($server,$workerid){
	// echo "workerstart: ".$workerid.PHP_EOL;
	// echo PHP_EOL;
});
$serv->on("task","on_task");
$serv->on("finish",function($serv,$task_id,$data){
    return ;
});
$serv->on('close', function($server,$fd,$from_id) {
	// echo "connection close: ".$fd.PHP_EOL;
	// echo PHP_EOL;
});
$serv->start();
function on_task($serv,$task_id,$from_id,$data) {
    switch ($data['type']){
        case 'login':
            $send_msg="说:我来了~";
            break;
        default:
            $send_msg="说:{$data['msg']['speak']}";
            break;
    }
    foreach ($serv->connections as $conn){
        if ($conn!=$data['fd']){
            if (strpos($data['msg']['name'],"游客")===0){
                $name=$data['msg']['name']."_".$data['fd'];
            }else{
                $name=$data['msg']['name'];
            }
        }else{
            $name="我";
        }
        $serv->push($conn,$name.$send_msg);
    }
    return;
}
function on_finish($serv,$task_id,$data){
    return true;
}
【前端代码】
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>WebSocket测试</title>
<script language="javascript"type="text/javascript" src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js">
</script>
</head>
<body>
<h2>WebSocket Test</h2>
昵称:<input type="text" id="name" size="5" value="游客"/> <input type="text" id="content">
<button onclick="speak_to_all()">发送</button>
<br/><br/>
<textarea id="message" style="overflow-x:hidden" rows="10" cols="50"></textarea>
<div id="output"></div>
</body>
<script language="javascript"type="text/javascript">
    var wsUri ="ws://188.131.152.71:9502/"; 
    var output;  
    function init() { 
        output = document.getElementById("output"); 
        testWebSocket();
    }
    function testWebSocket() { 
        websocket = new WebSocket(wsUri); 
        websocket.onopen = function(evt) { 
            onOpen(evt) 
        }; 
        websocket.onclose = function(evt) { 
            onClose(evt) 
        }; 
        websocket.onmessage = function(evt) { 
            onMessage(evt) 
        }; 
        websocket.onerror = function(evt) { 
            onError(evt) 
        }; 
}
    function get_speak_msg(){
        var name=document.getElementById("name").value;
        var speak=document.getElementById("content").value;
        var json_msg='{"name":"'+name+'","speak":\"'+speak+'"}';
        return json_msg;
    }
    function pack_msg(type,msg){
        return '{"type":"'+type+'","msg":'+msg+'}';
    }
    function onOpen(evt) {
        append_speak("已经联通服务器.........");
        speak_msg=get_speak_msg();
        send_msg=pack_msg("login",speak_msg);
        doSend(send_msg);
    }
    function onClose(evt) { 
        append_speak("俺老孙去也!");
    } 
    function onMessage(evt) {
        append_speak(evt.data);
    }
    function onError(evt) {
        alert(evt.data);
    }
    function doSend(message) { 
        websocket.send(message);
    }
  
    function append_speak(new_msg){
        document.getElementById("message").value=document.getElementById("message").value+new_msg+"\n";
        document.getElementById('message').scrollTop = document.getElementById('message').scrollHeight;
    }
    function speak_to_all(){
        send_msg=pack_msg("speak",get_speak_msg());
        if(document.getElementById("content").value==""){
            return;
        }
        doSend(send_msg);
        document.getElementById("content").value="";
    }
init();
</script>
</html>
                    
                
                
            
        
浙公网安备 33010602011771号