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>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM