swoolechat.php
<?php
use Swoole\Coroutine as co;
class swoolechat {
//協程內部的變量
public $sql_string=null;
public $sql_res=null;
public $map=null;
//公共變量
public $ws;
public $configws=array(
'worker_num' => 1,//進程數 進程數越多,負載能力越大,建議cpu核數2倍
'max_request' => 10000,//進程處理完這么多任務數,就會重啟,防止溢出
'max_conn'=>10000,//最大保持連接數,也就是同時在線人數
'ipc_mode' => 1,//1使用unix socket通信2使用消息隊列通信3使用消息隊列通信,並設置為爭搶模式
'dispatch_mode' => 2,//2固定模式,同一個鏈接只被一個worker處理,1輪詢模式3爭搶模式
'debug_mode'=> 1 ,
'daemonize' => 0,//守護模式
'log_file' => '\log\swoole.log',
'heartbeat_check_interval' => 30,//心跳偵測時間間隔
'heartbeat_idle_time' => 600,//閑置時間上線
);
public $configsql=array(
'host'=>'127.0.0.1',
'port'=>3306,
'user'=>'ws_ltcpi_com',
'password'=>'La2bKpT4T2xrrkLL',
'database'=>'ws_ltcpi_com',
'charset'=>'utf8',
'timeout'=>10,
);
//構造函數
public function __construct() {
//創建websocket服務器對象,監聽0.0.0.0:端口
$this->ws = new swoole_websocket_server("0.0.0.0", 9501);
$this->ws->set($this->configws);
//監聽WebSocket連接
$this->ws->on('open', function ($ws, $request) {
echo "server: handshake success with fd{$request->fd}\n";
$this->ws->push($request->fd, "hello, welcome\n");
});
//監聽WebSocket收到信息
$this->ws->on('message', function ($ws, $frame) {
// echo "onmessage: handshake success with fd{$frame}\n";
self::onmessage($ws,$frame->fd,$frame->data);
});
//關閉事件
$this->ws->on('close', function ($ws, $fd) {
echo "client-{$fd} is closed\n";
});
//啟動服務
echo "啟動3服務\n";
$this->ws->start();
}
//內部方法
protected function get_sql_insert($table,$arr){
$sql=" insert into ".$table." (";
foreach (array_keys($arr) as $k=>$v){
$sql.=$v.',';
}
$sql=rtrim($sql, ",");
$sql.=') values (';
foreach ($arr as $k=>$v){
$sql.="'".$v."',";
}
$sql=rtrim($sql, ",");
$sql.=')';
return $sql;
}
protected function get_sql_delete_fd($fd){
$res="DELETE FROM fa_fdband WHERE fd = '{$fd}'";
return $res;
}
protected function get_sql_delete_userid($userid){
$res="DELETE FROM fa_fdband WHERE userid = '{$userid}'";
return $res;
}
protected function pushtofd($fd,$type,$status,$msg){
$res=json_encode(array('type'=>$type,'status'=>$status,'msg'=>$msg));
$this->ws->push($fd,utf8_encode($res));
}
protected function get_sql_bandlist($fd){
$sql="select * from fa_fdband where fd='{$fd}'order by id desc";
return $sql;
}
//收到命令
public function onmessage($ws,$fd,$data){
//獲取fd 數組數據
$data_arr=json_decode($data, true);
if ($data=='heart' or array_key_exists('type',$data_arr)==false){
//心跳回復
$ws->push($fd,'heart');
}else{
$type=$data_arr['type'];
//登錄房間
if ($type=='band'){
$roomid=$data_arr['roomid'];
$userid=$data_arr['userid'];
self::band($fd,$roomid,$userid);
}
//聊天
if ($type=='chatsend'){
$msg=$data_arr['msg'];
self::chatsend($fd,$msg);
}
}
}
//綁定房間
public function band($fd,$roomid,$userid){
//生成刪除語句 插入語句
$this->map=array(
'fd'=>$fd,
'userid'=>$userid,
'roomid'=>$roomid,
'createtime'=>time(),
);
go(function() {
$db=new co\MySQL();
$db->connect($this->configsql);
//獲取變量
$fd=$this->map['fd'];
$roomid=$this->map['roomid'];
$userid=$this->map['userid'];
//刪除同fd房間
$res=$db->query(self::get_sql_delete_fd($fd));
var_dump(self::get_sql_delete_fd($fd));
var_dump($res);
if ($res!=1){
self::pushtofd($fd,'band',0,'登錄房間失敗,刪除同fd失敗');
}
//刪除同userid綁定信息
$res=$db->query(self::get_sql_delete_userid($userid));
if ($res!=1){
self::pushtofd($fd,'band',0,'登錄房間失敗,刪除同userid失敗');
}
//創建房間
$res=$db->query(self::get_sql_insert('fa_fdband',$this->map));
if ($res==1){
self::pushtofd($this->map['fd'],'band',1,'登錄房間成功');
}else{
self::pushtofd($this->map['fd'],'band',0,'登錄房間失敗,因為插入失敗');
}
});
}
public function chatsend($fd,$msg){
$this->map=array(
'fd'=>$fd,
'msg'=>$msg,
);
go(function() {
$db=new co\MySQL();
$db->connect($this->configsql);
//獲取變量
$fd=$this->map['fd'];
$msg=$this->map['msg'];
//根據fd查詢綁定信息
$band_list=$db->query(self::get_sql_bandlist($fd));
if (count($band_list)<1){
self::pushtofd($this->map['fd'],'chatsend',0,'請先綁定房間');
return;
}
//保存記錄
$map=array(
'userid'=>$band_list[0]['userid'],
'roomid'=>$band_list[0]['roomid'],
'msg'=>$msg,
'createtime'=>time(),
);
//生成保存消息語3句
$res=$db->query(self::get_sql_insert('fa_fdchat',$map));
var_dump(self::get_sql_insert('fa_fdchat',$map));
var_dump($res);
self::pushtofd($this->map['fd'],'chatsend',1,'success');
//轉發消息
$band_list=$db->query("select * from fa_fdband where roomid='{$map['roomid']}'order by id desc");
foreach ($band_list as $k=>$v){
if ($v['fd']==$fd){
$msg=array(
'nickname'=>'我',
'msg'=>$map['msg']
);
self::pushtofd($v['fd'],'chatrev',1,$msg);
}else{
$msg=array(
'nickname'=>'追風少年',
'msg'=>$map['msg']
);
self::pushtofd($v['fd'],'chatrev',1,$msg);
}
}
});
}
}
$obj=new SwooleChat();
client.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>webSocket客戶端接收命令</title>
</head>
<body>
<p id="status"></p>
<input type="text" id="login" style="width: 500px" value='{"type":"band","roomid":"3","userid":"4"}'/>
<button onclick="login()">綁定房間</button>
<br/>
<input type="text" id="chat" style="width: 500px" value='{"type":"chatsend","msg":"大家好我是新人4"}'/>
<button onclick="chat()">發送消息</button>
<!--<button onclick="clientClose()">關閉連接</button>-->
<!--<button onclick="clientBreak()">徹底斷開</button>-->
<script type="text/javascript">
var lockReconnect = false;//避免重復連接
var wsUrl = "ws://124.156.153.202:9501"; // websocket鏈接
var ws;
function decodeUnicode(str) {
str = str.replace(/\\/g, "%");
return unescape(str);
}
createWebSocket();
// 創建websocket
function createWebSocket(){
try {
ws = new WebSocket(wsUrl);
ws.onopen = function (evt) {
onOpen(evt);
};
ws.onclose = function (evt) {
onClose(evt);
websocketReconnect(wsUrl);
};
// 接收服務端數據時觸發事件
ws.onmessage = function (evt) {
onMessage(evt);
};
// 通信發生錯誤時觸發
ws.onerror = function (evt) {
websocketReconnect(wsUrl);
onError(evt);
};
} catch (e) {
console.log('catch');
websocketReconnect(wsUrl);
}
}
//被動業務
function onOpen(evt) {
document.getElementById('status').innerText += "receive:" + "建立鏈接成功..." + "\n";
//心跳檢測重置
heartCheck.start();
}
function onClose(evt) {
document.getElementById('status').innerText += "receive:" + "連接已關閉..." + "\n";
}
function onMessage(evt) {
if (evt.data!=='heart'){
document.getElementById('status').innerText += "receive:" + decodeUnicode(evt.data)+ "\n";
}
heartCheck.start();
}
function onError(evt) {
document.getElementById('status').innerText += "通信錯誤"+ "\n";
}
//重新連接
function websocketReconnect(url) {
if (lockReconnect) { // 是否已經執行重連
return;
}else {
lockReconnect = true;
//沒連接上會一直重連,設置延遲避免請求過多
tt && clearTimeout(tt);
var tt = setTimeout(function () {
createWebSocket(url);
lockReconnect = false;
}, 5000);
}
}
//發送心跳
var heartCheck = {
timeout: 5000,
timeoutObj: null,
serverTimeoutObj: null,
start: function () {
var self = this;
this.timeoutObj && clearTimeout(this.timeoutObj);
this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
this.timeoutObj = setTimeout(function () {
ws.send("heart");
console.log('send:start');
self.serverTimeoutObj = setTimeout(function () {
ws.close();
}, self.timeout);
}, this.timeout)
}
};
//主動業務
function login() {
ws.send(document.getElementById('login').value);
}
function chat() {
ws.send(document.getElementById('chat').value);
}
function clientClose() {
ws.close();
document.getElementById('status').innerText += "客戶端主動普通斷開" +"\n";
}
</script>
</body>
</html>
sql
https://files.cnblogs.com/files/bufeetu/websocket.7z