在chat程序中,addClientToRoom有一個(gè)// 獲取所有所有房間的實(shí)際在線客戶端列表,以便將存儲(chǔ)中不在線用戶刪除
$all_online_client_id = Gateway::getOnlineStatus(); 這句話的調(diào)用,不知道為何這么做?
難道心跳消息檢測(cè)失敗,服務(wù)器不會(huì)拋出onClose事件?
如果這句話在每次新用戶加入聊天時(shí)調(diào)用,性能實(shí)在有些太差了,并且獲取時(shí)也沒有room_id參數(shù),獲取所有在線用戶。
謝謝。
另外對(duì)于房間里面用戶列表的Store,如果是redis的話,應(yīng)該是可以把 $handler = fopen(__FILE__, 'r');
flock($handler, LOCK_EX); 類似這樣的代碼刪除掉的吧
我用手機(jī)測(cè)試了下,好像不會(huì)自動(dòng)移出。
后臺(tái)日志:
client:192.168.1.100:58876 gateway:127.0.0.1:3008 client_id:8 session:{"room_id":1,"client_name":"ooo"} onMessage:{"type":"pong"}
client:127.0.0.1:64599 gateway:127.0.0.1:3005 client_id:6 session:{"room_id":1,"client_name":"12345"} onMessage:{"type":"say","to_client_id":"all","to_client_name":"所有人","content":",密密麻麻"}
client:127.0.0.1:64599 gateway:127.0.0.1:3005 client_id:6 session:{"room_id":1,"client_name":"12345"} onMessage:{"type":"pong"}
client:192.168.1.100:58876 gateway:127.0.0.1:3008 client_id:8 session:{"room_id":1,"client_name":"ooo"} onMessage:{"type":"pong"}
client:127.0.0.1:64599 gateway:127.0.0.1:3005 client_id:6 session:{"room_id":1,"client_name":"12345"} onMessage:{"type":"pong"}
client:192.168.1.100:58876 gateway:127.0.0.1:3008 client_id:8 session:{"room_id":1,"client_name":"ooo"} onMessage:{"type":"pong"}
========我把手機(jī)的wifi關(guān)掉,在這里之后,就沒有再給 client_id_8 發(fā)出心跳消息了
client:127.0.0.1:64599 gateway:127.0.0.1:3005 client_id:6 session:{"room_id":1,"client_name":"12345"} onMessage:{"type":"pong"}
client:127.0.0.1:64599 gateway:127.0.0.1:3005 client_id:6 session:{"room_id":1,"client_name":"12345"} onMessage:{"type":"pong"}
client:127.0.0.1:64599 gateway:127.0.0.1:3005 client_id:6 session:{"room_id":1,"client_name":"12345"} onMessage:{"type":"pong"}
client:127.0.0.1:64599 gateway:127.0.0.1:3005 client_id:6 session:{"room_id":1,"client_name":"12345"} onMessage:{"type":"pong"}
redis:
get ROOM_CLIENT_LIST-1
"a:2:{i:6;s:5:\"12345\";i:8;s:3:\"ooo\";}"
=========等了一會(huì),手機(jī)鎖屏了,然后終于有了
client:192.168.1.100:58876 gateway:127.0.0.1:3008 client_id:8 onClose:'' 調(diào)用
redis也正常了
=========再次測(cè)試,手機(jī)不鎖屏
client:192.168.1.100:58913 gateway:127.0.0.1:3006 client_id:9 session:null onMessage:{"type":"re_login","client_name":"ooo","room_id":1}
client:127.0.0.1:64599 gateway:127.0.0.1:3005 client_id:6 session:{"room_id":1,"client_name":"12345"} onMessage:{"type":"pong"}
client:192.168.1.100:58913 gateway:127.0.0.1:3006 client_id:9 session:{"room_id":1,"client_name":"ooo"} onMessage:{"type":"pong"}
client:127.0.0.1:64599 gateway:127.0.0.1:3005 client_id:6 session:{"room_id":1,"client_name":"12345"} onMessage:{"type":"pong"}
client:127.0.0.1:64599 gateway:127.0.0.1:3005 client_id:6 session:{"room_id":1,"client_name":"12345"} onMessage:{"type":"pong"}
client:127.0.0.1:64599 gateway:127.0.0.1:3005 client_id:6 session:{"room_id":1,"client_name":"12345"} onMessage:{"type":"pong"}
client:127.0.0.1:64599 gateway:127.0.0.1:3005 client_id:6 session:{"room_id":1,"client_name":"12345"} onMessage:{"type":"pong"}
client:127.0.0.1:64599 gateway:127.0.0.1:3005 client_id:6 session:{"room_id":1,"client_name":"12345"} onMessage:{"type":"pong"}
client:127.0.0.1:64599 gateway:127.0.0.1:3005 client_id:6 session:{"room_id":1,"client_name":"12345"} onMessage:{"type":"pong"}
client:127.0.0.1:64599 gateway:127.0.0.1:3005 client_id:6 session:{"room_id":1,"client_name":"12345"} onMessage:{"type":"pong"}
worker exit with status 11 =========日志里面有了句這個(gè),但是一直沒看到 onClose 調(diào)用
client:127.0.0.1:64599 gateway:127.0.0.1:3005 client_id:6 session:{"room_id":1,"client_name":"12345"} onMessage:{"type":"pong"}
client:127.0.0.1:64599 gateway:127.0.0.1:3005 client_id:6 session:{"room_id":1,"client_name":"12345"} onMessage:{"type":"pong"}
client:127.0.0.1:64599 gateway:127.0.0.1:3005 client_id:6 session:{"room_id":1,"client_name":"12345"} onMessage:{"type":"pong"}
=====截止到現(xiàn)在,redis里面這個(gè)房間依然是有兩個(gè)用戶,估計(jì)后續(xù)也不會(huì)調(diào)用onClose了。
請(qǐng)問群主能否解釋下,服務(wù)器心跳檢測(cè),調(diào)用onClose的規(guī)則?
/**
* 心跳邏輯
* @return void
*/
public function ping()
{
// 遍歷所有客戶端連接
foreach($this->_clientConnections as $connection)
{
// 上次發(fā)送的心跳還沒有回復(fù)次數(shù)大于限定值就斷開
if($this->pingNotResponseLimit > 0 && $connection->pingNotResponseCount >= $this->pingNotResponseLimit)
{
$connection->destroy();
continue;
}
// $connection->pingNotResponseCount為-1說明最近客戶端有發(fā)來消息,則不給客戶端發(fā)送心跳
if($connection->pingNotResponseCount++ >= 0)
{
if($this->pingData)
{
$connection->send($this->pingData);
}
}
}
}
如果在啟動(dòng)程序 start_gateway 里面加上 $gateway->pingNotResponseLimit = 3;
應(yīng)該會(huì)走到
$connection->destroy();continue;
這里,但是也調(diào)用不到Event.php里面的onClose事件處理函數(shù)吧,在 ping 里面加上顯示的調(diào)用?
// 獲取所有房間的實(shí)際在線客戶端列表,以便將存儲(chǔ)中不在線用戶刪除
$all_online_client_id = Gateway::getOnlineStatus(); 這句話的調(diào)用,不知道為何這么做?
實(shí)際正式部署時(shí)不需要這么做,
之所以加了這個(gè),主要是為了開發(fā)環(huán)境,
開發(fā)環(huán)境經(jīng)常要重啟服務(wù),重啟服務(wù)后所有客戶端都會(huì)斷開,
但是存儲(chǔ)中的房間用戶列表數(shù)據(jù)還在,
導(dǎo)致數(shù)據(jù)不一致,所以每個(gè)用戶登錄時(shí)都調(diào)用了getOnlineStatus,
目的是去掉由于重啟服務(wù)導(dǎo)致的數(shù)據(jù)不一致用戶。
這里可以優(yōu)化空間,比如在啟動(dòng)腳本里面加上鉤子函數(shù),
服務(wù)停止時(shí)清空房間用戶數(shù)據(jù)存儲(chǔ)(要注意是否有分布式部署,不要把其它機(jī)器的用戶清除了)
或者用定時(shí)器定時(shí)清除不在線用戶,而不是每次登錄都調(diào)用getOnlineStatus。
心跳檢測(cè)參考手冊(cè)
http://gatewayworker-doc.workerman.net/gateway-worker-development/heartbeat.html
手機(jī)關(guān)閉網(wǎng)絡(luò)算是異常斷開,和拔網(wǎng)線類似,
客戶端不會(huì)發(fā)送fin包,服務(wù)端也就不會(huì)立刻檢測(cè)到網(wǎng)絡(luò)已經(jīng)不通,
這種情況需要設(shè)置應(yīng)用層心跳,并且設(shè)置pingNotResponseLimit不為0,
可以快速檢測(cè)這種網(wǎng)絡(luò)異常情況
onClose
見手冊(cè)
http://gatewayworker-doc.workerman.net/gateway-worker-development/onclose.html
不管是誰斷開,只要服務(wù)端檢測(cè)到連接已經(jīng)斷開,就會(huì)觸發(fā)
鎖
另外對(duì)于房間里面用戶列表的Store,如果是redis的話,應(yīng)該是可以把 $handler = fopen(__FILE__, 'r');
flock($handler, LOCK_EX); 類似這樣的代碼刪除掉的吧
不能簡(jiǎn)單的直接去掉鎖,讀取列表+保存列表并非原子操作,多進(jìn)程同時(shí)讀取+保存時(shí)會(huì)有并發(fā)問題,當(dāng)然你可以利用redis提供的接口保證原子性,那樣可以去掉鎖