一直不能下決心好好學習,仔細研究一下,決定用盡量降低難度曲線的方法,從易到難,一步一步的學習,所以整了個demo專案。
git倉庫和使用步驟
確保能看到swoole,在 php -m 命令中
php -m
git clone https://github.com/lang123789/swoole_demo.git
然後設定了標籤,本文對應 v4.0
cd swoole_demo
git checkout v4.0
有提示錯誤之類,但程式碼已經切換到 v4.0 了。
另外,前面3版其實有一些js錯誤,一併修復了。
## 安裝類庫,生成 autoload.php 檔案
composer install
## 啟動 websocket 服務
php src/WebSocket/run.php
需求
6、需要能正常聊天。就是別人說話,其他每個在聊天室的人都能看到這個人說的話。
7、如果某人上線,他自己看到 歡迎您,某某某,其他人看到,某某某 上線了。
8、如果某人下線。其他人看到,某某某 下線了。
測試網址
127.0.0.1/index.php?id=1
127.0.0.1/index.php?id=2
主要程式碼
客戶端主要程式碼
客戶端程式碼主要在 index.php 中
function activate_chat_js() {
const me = 1;
const chatter = 0;
// 這是每個人自己發訊息。子程式1。
function update_chatWindow(incoming_message, from) {
if (from === 1) {
var msg_html = my_message_html(incoming_message);
} else if (from === 0) {
var msg_html = chatter_message_html(incoming_message);
}
$(".chat-window").append(msg_html);
}
// 這是自己發訊息。子程式2。
function my_message_html(incoming_message) {
var newMessage = '<div class="me-wrapper">' + '<div class="me-message container">' + incoming_message + '</div>' + '<div class="me-avatar">' + '我自己' +
'</div></div>';
return newMessage;
}
// click btn to send message
// 這也是每個人自己發訊息。最開始點選。
$("#btn-send-message").click(function () {
var user_input_area = $("#user-input-value");
if (user_input_area.text().length == 0) {
} else {
var message=user_input_area.text();
update_chatWindow(user_input_area.text(), 1);
user_input_area.text("");
$('.chat-window').scrollTop($('.chat-window')[0].scrollHeight);
// v4.0修改,把訊息給伺服器。
window.websocket.send("my_message|{$user_id}|"+ message);
}
});
// ctrl+enter send message
// 這也是每個人自己發訊息,用Enter鍵。
$('#user-input-value').keydown(function (e) {
if ((event.keyCode == 10 || event.keyCode == 13)) {
$('#btn-send-message').trigger("click");
event.cancelBubble = true;
event.preventDefault();
}
});
}
// 這是顯示在中間的系統訊息。由伺服器推送。
function system_chatWindow(incoming_message) {
var msg_html = '<div class="system-message">' + incoming_message + '</div>' ;
$(".chat-window").append(msg_html);
$('.chat-window').scrollTop($('.chat-window')[0].scrollHeight);
}
// v4.0 ,這是被onmessage函式呼叫的方法,
// 這是其他人發的訊息,廣播到每個機器。
function update_chatWindow2(incoming_message, from) {
var msg_html = '<div class="current-chatter-wrapper">' + '<div class="chatter-avatar">' + from + '</div>' + '<div class="chatter-message container">' + incoming_message + '</div>' + '</div>';
$(".chat-window").append(msg_html);
$('.chat-window').scrollTop($('.chat-window')[0].scrollHeight);
}
window.onload = function(){ activate_chat_js();
var wsServer = 'ws://{$JS_IP}:9501';
var websocket = new WebSocket(wsServer);
window.websocket = websocket;
websocket.onopen = function (evt) {
console.log("Connected to WebSocket server.");
websocket.send("my_id|{$user_id}");
};
websocket.onclose = function (evt) {
console.log("Disconnected");
};
websocket.onmessage = function (evt) {
console.log('Retrieved data from server: ' + evt.data);
var user = JSON.parse(evt.data);
if (user.type=='my_id'){
system_chatWindow(user.message);
}
// v4.0修改。其他人接受某人的訊息廣播。
if (user.type=='my_message'){
update_chatWindow2(user.message, user.from_user_name );
}
};
websocket.onerror = function (evt, e) {
console.log('Error occured: ' + evt.data);
};
}
服務端主要程式碼
public function message(\swoole_websocket_server $server, \swoole_websocket_frame $frame)
{
$data = $frame->data;
echo "有訊息:".$data."\n";
//這裡使用者發來的資訊已經分型別了。my_id開頭,說明是系統自動從客戶端傳送的資訊,用於識別身份。
if (preg_match('#^my_id#', $data)) {
$user_id = explode("|", $data)[1];
$arr = $this->user_all;
$user_name = isset($arr[$user_id]) ? $arr[$user_id] : '';
if (!$user_name) {
//如果使用者不存在,則我直接關閉連線。
echo "非法連線。使用者id:" . $user_id;
$server->close($frame->fd);
return;
}
$user = [
'fd' => $frame->fd,
'user_name' => $user_name,
'user_id' => strval($user_id),
];
echo "有個人剛上線,資料:" . json_encode($user, JSON_UNESCAPED_UNICODE);
echo "\n";
// 放入記憶體表
$this->table->set($frame->fd, $user);
//給本人看 歡迎您。
$server->push($frame->fd, json_encode([
'type' => 'my_id',
'message' => '歡迎您,' . $user_name,
]));
// 通知其他人 某某 上線了。
foreach ($this->table as $row) {
if ($row['fd'] != $frame->fd) {
$server->push($row['fd'], json_encode([
'type' => 'my_id',
'message' => $user_name . ' 上線了',
]));
}
}
} elseif (preg_match('#^my_message#', $data)) {
$user_id = explode("|", $data)[1];
$message = explode("|", $data)[2];
$arr = $this->user_all;
$user_name = isset($arr[$user_id]) ? $arr[$user_id] : '';
if (!$user_name) {
//如果使用者不存在,則w我直接關閉連線。
echo "非法連線。使用者id:" . $user_id;
$server->close($frame->fd);
return;
}
echo "有人發訊息,內容:" . $message;
echo "\n";
// 通知其他人 ,進行廣播
foreach ($this->table as $row) {
if ($row['fd'] != $frame->fd) {
echo "推送訊息:" . $message."給fd:" . $row['fd'] ;
$server->push($row['fd'], json_encode([
'type' => 'my_message',
'message' => $message,
'from_user_name' => $user_name,
]));
}
}
}
}
/**
* 客戶端關閉的時候
*
* @param \swoole_websocket_server $server
* @param int $fd
*/
public function close(\swoole_websocket_server $server, int $fd)
{
$user = $this->table->get($fd);
$user_name = $user['user_name'];
echo "有人下線,資料:" . json_encode($user, JSON_UNESCAPED_UNICODE);
$this->table->del($fd);
// 通知其他人 某某 下線了。
foreach ($this->table as $row) {
$server->push($row['fd'], json_encode([
'type' => 'my_id',
'message' => $user_name . ' 下線了',
]));
}
}
WebSocketServer.php 是核心檔案。
程式碼說明
這一版的功能總算象個樣子了!
swoole挺好用的。
效果示例
本作品採用《CC 協議》,轉載必須註明作者和本文連結