
一、php安裝擴展組件Swoole
參考連接
二、配置linux服務器
在站點的組態檔中#SSL-END下面添加代碼
location /wss/ {
#通過配置埠指向部署websocker的專案
proxy_pass http://127.0.0.1:9205/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header X-real-ip $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
}
注意:
1、埠號不能與同服務器的wss一樣
2、 開放對應的埠(9205)
三、配置微信小程式socket合法域名

注意:后面不需要加埠 ,在站點的組態檔中已經做了定向
四、服務器命令執行wss.php檔案(以下命令請在wss.php檔案對應的目錄執行)
測驗啟動:php wss.php
設定常駐:nohup php -f wss.php
執行完成后,在對應的檔案目錄下面會生成一個nohup.out記錄檔案(不要洗掉這個檔案)
查看行程:netstat -ntlp
結束行程:kill 行程編號
注意:上線一定要執行常駐命令,不執行會報錯,因為終端關閉后就無法建立連接,
終端:

nohup.out檔案:

五、微信小程式創建連接
在小程式全域app.js初始化時執行創建連接
var util = require("pages/utils/util.js");
var websocket = require("pages/utils/websocket.js");
//app.js
App({
//全域變數
globalData: {
swook_url: "wss://*********/wssc/",
//webSocket
WebSocketSendMsgCallback: function () {},
},
/**
* 當小程式初始化完成時,會觸發 onLaunch(全域只觸發一次)
*/
onLaunch: function () {
var that = this;
//心跳設定
var userInfo = wx.getStorageSync('userInfo') || {};
if (userInfo.id) { //必須在登錄狀態下才可以連接
that.linkWebsocket(userInfo);
}
},
/**
* 當小程式從前臺進入后臺,會觸發 onHide
*/
onHide: function () {
var that = this;
},
/**
* 當小程式發生腳本錯誤,或者 api 呼叫失敗時,會觸發 one rror 并帶上錯誤資訊
*/
one rror: function (msg) {
},
//開啟WebSocket
linkWebsocket: function (userInfo) {
var that = this;
wx.connectSocket({
url: that.globalData.swook_url,
success(res) {
console.log('連接成功~')
wx.onSocketOpen(() => {
console.log('WebSocket連接打開');
//第一次創建連接成功時獲取分配的$fd存入資料庫,系結用戶
wx.sendSocketMessage({
data: JSON.stringify({
pages: 'A_member',
act: 'initSocket',
member_id: userInfo.id,
content: 'initSocket',
})
})
//資料回傳處理
wx.onSocketMessage((res) => {
var objData = JSON.parse(res.data);
if (objData.code == "600") {
//處理資料
that.globalData.WebSocketSendMsgCallback(objData);
}
})
//連接成功打開,拉起心跳檢測
websocket.linkWebsocket_xin(40000, true);
})
},
});
wx.onSocketError(function (res) {
console.log('打開失敗~,請聯系管理員');
});
}
})
pages\utils\websocket.js
注意:發送資訊時也算是一次心跳,所以在發送資訊之前把當前的心跳關閉,發送成功之后再以發送成功時的時間再次建立心跳連接,
例如:我在10:00:00發送的心跳連接,下次的心跳應該是10:00:40,但是我在10:00:10時發送了一條資訊,那么下次的心跳連接時間應該是10:00:50
//心跳重連檢測
function linkWebsocket_xin(lian_time, mag) {
if (mag == true) {
var dingshi_title = '';
dingshi_title = setInterval(function () {
console.log("當前心跳已重新連接");
//回圈執行代碼
wx.sendSocketMessage({
data: JSON.stringify({
pages: 'A_member',
act: 'ping',
}),
fail(res) {
// console.log(res)
}
});
}, lian_time) //回圈時間,注意不要超過1分鐘
wx.setStorageSync('dingshi_title', dingshi_title);
} else {
var dingshi_title = wx.getStorageSync('dingshi_title') ? wx.getStorageSync('dingshi_title') : '';
//關閉定時器
clearInterval(dingshi_title);
console.log("當前心跳已關閉");
}
}
//發送訊息
function send(msg) {
//關閉定時器
linkWebsocket_xin(40000, false);
wx.sendSocketMessage({
data: msg,
success(res) {
//重置定時器時間
linkWebsocket_xin(40000, true);
},
fail(res) {
// console.log(res)
}
});
}
module.exports = {
send: send,
linkWebsocket_xin: linkWebsocket_xin,
}
六、發送訊息,推送原理
例如在一個聊天室中存在5個人,那么這個聊天室會系結這5個人的會員ID,利用會員ID在獲取創建swook連接時分配的$fd,在分別進行通知,通知時需驗證當前的$fd是否有效,
那么通知內容應該是什么呢?
我做的是,發送訊息成功存入資料庫后對小程式進行回傳時,進行通知
例如:
//注意引入websocket.js
//內容行程提交
websocket.send(
JSON.stringify({
pages: 'A_member',
act: 'add',
detailId: that.data.detailId,//當前聊天室ID
message: data.fan_arr,//發送的內容
}),
);
七、wss.php檔案
面向程序和面向物件的寫法官方給了哈 <<點擊進入
<?php
header("Content-Type: application/json; charset=utf-8");
include 'inc_serve.php';
class WebsocketTest {
public $server;
public function __construct() {
$this->server = new Swoole\WebSocket\Server("0.0.0.0", 9205);
$this->server->on('open', function (swoole_websocket_server $server, $request) {//用于指定連接成功后的回呼函式
echo date("Y-m-d H:i:s") . ":用戶 fd{$request->fd} 成功鏈接\n";
});
$this->server->on('message', function (Swoole\WebSocket\Server $server, $frame) {//用于指定收到服務器資料后的回呼函式
// echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
// $server->push($frame->fd, "this is server");
// //參考
$conn = _conn();
$infoArray = array();
$infoArray["code"] = 0;
$infoArray["msg"] = "REQUEST FAILED";
$webSocket_id = $frame->fd;
$webSocket_data = $frame->data;
$webSocket_data = htmlspecialchars_decode($webSocket_data);
$webSocket_data = $webSocket_data ? json_decode($webSocket_data, true) : array();
if(!is_array($webSocket_data)){
$webSocket_data = array();
}
$pages = $webSocket_data["pages"];
$act = $webSocket_data["act"];
$detailId = (int)$webSocket_data["detailId"];
$member_id = (int)$webSocket_data["member_id"];
$message = $webSocket_data["message"];
//log
echo date("Y-m-d H:i:s") . ":用戶 fd{$frame->fd} 發送訊息 {$pages},{$act},{$detailId}\n";
if($pages == "A_member"){
if($act=="initSocket"){
//首次握手用戶系結
_wss_member_fid($this->server, $conn, $webSocket_id, $member_id);
$infoArray["code"] = 200;
$infoArray["msg"] = "initSocket success";
}elseif($act=='add'){//發送訊息回傳
// $infoArray["code"] = 200;
// $infoArray["msg"] = "OK";
include ("A_chat.php");
}elseif($act=='ping'){//心跳連接
$infoArray["code"] = 666;
$infoArray["msg"] = "OK_xin";
$infoArray["content"] = "pong";
}
}
//發送
$json = json_encode($infoArray, true);
$server->push($webSocket_id, $json);
});
$this->server->on('close', function ($ser, $webSocket_id) {//用于指定連接關閉后的回呼函式
//echo "client {$fd} closed\n";
//參考
$infoArray["code"] = 200;
$infoArray["msg"] = "initSocket success";
$infoArray["webSocket_id"] = $webSocket_id;
$conn = _conn();
//獲取
if($webSocket_id){
$sqlrm = "select * from a_member where webSocket_id='".$webSocket_id."' ";
$resultrm = mysqli_query($conn,$sqlrm);
$rm = mysqli_fetch_array($resultrm);
//log
echo date("Y-m-d H:i:s") . ":用戶 fd{$webSocket_id} 關閉鏈接\n";
//清除狀態
$sqlEdit = "update a_member set webSocket_id=0 where webSocket_id={$rm["webSocket_id"]}";
$resultEdit = mysqli_query($conn,$sqlEdit);
}
});
$this->server->on('request', function ($request, $response) {
// 接收http請求
echo "request\n";
echo json_encode($request)."\n";
echo json_encode($response)."\n";
echo $request->get['message']."\n";
// // 接收http請求從get獲取message引數的值,給用戶推送
// // $this->server->connections 遍歷所有websocket連接用戶的fd,給所有用戶推送
// foreach ($this->server->connections as $fd) {
// // 需要先判斷是否是正確的websocket連接,否則有可能會push失敗
// if ($this->server->isEstablished($fd)) {
// $this->server->push($fd, $request->get['message']);
// }
// }
});
$this->server->start();
}
}
new WebsocketTest();
?>
八、發送訊息回傳
WebSocketSendMsgCallback,這個是實時回傳,
wx.onSocketMessage((res) => {
var objData = JSON.parse(res.data);
if (objData.code == "600") {
//處理資料
that.globalData.WebSocketSendMsgCallback(objData);
}
})
接收資料:
app.globalData.WebSocketSendMsgCallback = function (data) {
if (data.act == "chat_room_list" && data.pages == "A_chat") {
var subjects = that.data.subjects;
var message = data.message;
if (data.member_id == userInfo.id) {
message[0].admin = 1;
} else {
message[0].admin = 2;
}
subjects = subjects.concat(message);
that.setData({
subjects,
})
}
}
九、日志查看

另外還有就是如果服務器重啟了,需要服務器再次執行wss.php檔案
當會員退出登錄時,那么當前的連接應該斷了wx.closeSocket();
wss.php檔案中有監聽斷開的處理,應該是把系結會員的fd清除,
如果會員登錄時,那么應該在次建立連接
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/290044.html
標籤:其他
