## start_io.php 完整代碼,含二開調試內容,輔助用戶深入理解交互代碼邏輯 ??
<div style="width:100%;padding:20px; height: 360px; background-color: #ffffff; border-radius: 10px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);">
<h2 >講解</h2>
??、啟動一個端口為2120的socket的服務`$sender_io = new SocketIO(2120);`
??、客戶端連接以后所有的回調事件都在這個里面處理`$sender_io->on('connection', function($socket){`
??、`$socket->on('login'` 是本文檔里面定義的login回調事件用于綁定用戶id進行登錄注冊并且回調
??、`$socket->on('send_message'` 是響應前端的`send_message`事件發送過來的消息,處理的結果發送給前端代碼中綁定的`new_msg`事件。
??、切記一點就是每一個監聽的on的回調,前后端都是對應的。不可能前端有后端沒有,也不可能后端有前端沒有。成對出現的,相當于一個錨點。
??、前后端都無需單獨配置心跳,socket.io自帶心跳
</div>
*****
```
<?php
use Workerman\Worker;
use Workerman\Timer;
use PHPSocketIO\SocketIO;
use Workerman\Protocols\Http\Request;
use Workerman\Connection\TcpConnection;
include __DIR__ . '/vendor/autoload.php';
// 全局數組保存uid在線數據
$uidConnectionMap = array();
// 記錄最后一次廣播的在線用戶數
$last_online_count = 0;
// 記錄最后一次廣播的在線頁面數
$last_online_page_count = 0;
// PHPSocketIO服務
$sender_io = new SocketIO(2120);
// 客戶端發起連接事件時,設置連接socket的各種事件回調
$sender_io->on('connection', function($socket){
// 當客戶端發來登錄事件時觸發
$socket->on('login', function ($uid)use($socket){
global $uidConnectionMap, $last_online_count, $last_online_page_count;
// 已經登錄過了
if(isset($socket->uid)){
return;
}
// 更新對應uid的在線數據
$uid = (string)$uid;
if(!isset($uidConnectionMap[$uid]))
{
$uidConnectionMap[$uid] = 0;
}
// 這個uid有++$uidConnectionMap[$uid]個socket連接
++$uidConnectionMap[$uid];
// 將這個連接加入到uid分組,方便針對uid推送數據
$socket->join($uid);
$socket->uid = $uid;
// 更新這個socket對應頁面的在線數據
$socket->emit('update_online_count', "當前<b>{$last_online_count}</b>人在線,共打開<b>{$last_online_page_count}</b>個頁面");
$socket->emit('new_msg', '鏈接成功了,開心吧');
});
//新增前端消息接收回調函數
$socket->on('send_message', function ($data)use($socket){
global $uidConnectionMap, $last_online_count, $last_online_page_count;
// 已經登錄過了
$data=json_decode($data,true);
$to = $data['to'];
$from = $socket->uid;
$msg=$data['msg'].'-消息來自:'.$from;
// $socket->emit('new_msg', '我接收到了你的消息:'.$msg);
$socket->to($to)->emit('new_msg', '我接收到了你的消息:'.$msg);
});
// 當客戶端斷開連接是觸發(一般是關閉網頁或者跳轉刷新導致)
$socket->on('disconnect', function () use($socket) {
if(!isset($socket->uid))
{
return;
}
global $uidConnectionMap, $sender_io;
// 將uid的在線socket數減一
if(--$uidConnectionMap[$socket->uid] <= 0)
{
unset($uidConnectionMap[$socket->uid]);
}
});
});
// 當$sender_io啟動后監聽一個http端口,通過這個端口可以給任意uid或者所有uid推送數據
$sender_io->on('workerStart', function(){
// 監聽一個http端口
$inner_http_worker = new Worker('http://0.0.0.0:2121');
// 當http客戶端發來數據時觸發
$inner_http_worker->onMessage = function(TcpConnection $http_connection, Request $request){
global $uidConnectionMap;
$post = $request->post();
$post = $post ? $post : $request->get();
// 推送數據的url格式 type=publish&to=uid&content=xxxx
switch(@$post['type']){
case 'publish':
global $sender_io;
$to = @$post['to'];
$post['content'] = htmlspecialchars(@$post['content']);
// 有指定uid則向uid所在socket組發送數據
if($to){
$sender_io->to($to)->emit('new_msg', $post['content']);
// 否則向所有uid推送數據
}else{
$sender_io->emit('new_msg', @$post['content']);
}
// http接口返回,如果用戶離線socket返回fail
if($to && !isset($uidConnectionMap[$to])){
return $http_connection->send('offline');
}else{
return $http_connection->send('ok');
}
}
return $http_connection->send('fail');
};
// 執行監聽
$inner_http_worker->listen();
// 一個定時器,定時向所有uid推送當前uid在線數及在線頁面數
Timer::add(1, function(){
global $uidConnectionMap, $sender_io, $last_online_count, $last_online_page_count;
$online_count_now = count($uidConnectionMap);
$online_page_count_now = array_sum($uidConnectionMap);
// 只有在客戶端在線數變化了才廣播,減少不必要的客戶端通訊
if($last_online_count != $online_count_now || $last_online_page_count != $online_page_count_now)
{
$sender_io->emit('update_online_count', "當前<b>{$online_count_now}</b>人在線,共打開<b>{$online_page_count_now}</b>個頁面");
$last_online_count = $online_count_now;
$last_online_page_count = $online_page_count_now;
}
});
});
if(!defined('GLOBAL_START'))
{
Worker::runAll();
}
```