2016-07-24 2 views
2

ラチェットウェブソケットでチャットルームをできるだけ早く設計しています。 ユーザーがいつそのページを離れるかを知っています。 例えば、ユーザ/クライアントがサーバとの接続を失った場合、クライアントとの接続が切断されていることをサーバに知らせることができません。では、チャットクライアントがインターネット接続を失って、もはやオンラインではないときをどのように追跡しますか?オンラインで誰かを確認するために半分の時間にラチェットウェブソケット - 切断されたクライアントを検出

  • サーバーをポーリングクライアントごとに15分:私は考えることができる

    2つの解決策。応答しないクライアントは切断されます。これはPHPで起こっているすべてのことを中断することなく行うことができますか?もしそうなら、どのように?コードはどこに置くのですか?私はaddPeriodicTimer()LoopInterfaceから見ましたが、それが仕事をするか、関数が自分のコードに収まるかわかりません。 sleep()も機能しません。この関数は(PHPで可能な場合)タイマーでありながら、私はまだPHP のメソッドは、ユーザーが実際にあらゆる状況で切断されたとき、これは検出できます

  • onClose()

  • バックグラウンドで他のタスクが起こってしたいですか?もしそうなら、このイベントが発生すると、どのユーザーが切断されたかをどのように知ることができますか? ConnectionInterfaceとメッセージは渡されません。

申し訳ありませんが、私はまだラチェットライブラリに新しいが、まだこのタスクを達成する方法を試してみてください。

server.phpというために私のコード:ちょうどテストとOnCloseのを確認した(:chat.php

<?php 

error_reporting(E_ALL^E_NOTICE); 
session_id($_GET['sessid']); 
    if(!session_id) 
     session_start(); 


$userid = $_SESSION["userid"]; 
$username = $_SESSION["username"]; 
$isadmin = $_SESSION["isadmin"]; 


use Ratchet\MessageComponentInterface; 
use Ratchet\ConnectionInterface; 

class Chat implements MessageComponentInterface 
{ 
    protected $clients; 

    public function __construct() 
    { 
     $this->clients = new \SplObjectStorage; 




    } 

    public function onOpen(ConnectionInterface $conn) 
    { 
     $this->clients->attach($conn); 

    } 

    public function onClose(ConnectionInterface $conn) 
    { 

     $this->clients->detach($conn); 
    } 

    public function onMessage(ConnectionInterface $conn, $msg) 
    { 
     $msgjson = json_decode($msg); 
     $tag = $msgjson->tag; 

     if($tag == "[msgsend]") 
     { 

      foreach($this->clients as $client) 
      { 
        $client->send($msg);  
      } 
     } 
     else if($tag == "[bye]") 
     { 

      foreach($this->clients as $client) 
      { 
        $client->send($msg);  
      } 

      onClose($conn); 
     } 
     else if($tag == "[connected]") 
     { 
      //store client information 


      //send out messages 
       foreach($this->clients as $client) 
      { 
        $client->send($msg);  
      } 



     } 







    } 

    public function onError(ConnectionInterface $conn, Exception $e) 
    { 
     echo "Error: " . $e->getMessage(); 
     $conn -> close(); 
    } 

} 

?> 

編集用app.js

// JavaScript Document 

var chat = document.getElementById("chatwindow"); 
var msg = document.getElementById("messagebox"); 
var refInterval = 0; 
var timeup = false; 
var awaytimer; 
var socket = new WebSocket("ws://52.39.48.172:8080"); 
var openn = false; 

function addMessage(msg){ 
     "use strict"; 
     chat.innerHTML += "<p>" + msg + "</p>"; 


} 

msg.addEventListener('keypress', function(evt){ 
    "use strict"; 
    if(evt.charCode != 13) 
     return; 

    evt.preventDefault(); 

    if(msg.value == "" || !openn) 
     return; 

    socket.send(JSON.stringify({ 
      msg: msg.value, 
      uname: nme, 
      uid: id, 
      tag: "[msgsend]" 


    })); 


    msg.value = ""; 



}); 

socket.onopen = function(evt) { 
    openn = true; 


    socket.send(JSON.stringify({ 
     uname: nme, 
     uid: id, 
     tag: "[connected]" 



    })); 




}; 

socket.onmessage = function(evt) { 
    var data = JSON.parse(evt.data); 

    if(data.tag == "[connected]") 
    { 
     addMessage(data.uname + " has connected..."); 

    } 
    else if(data.tag == "[bye]") 
    { 
     addMessage(data.uname + " has left the room..."); 

     if(data.uname == nme) 
      socket.close(); 
    } 
    else if(data.tag == "[msgsend]") 
    { 
     addMessage(data.uname + ": " + data.msg); 
    } 
}; 



    window.onfocus = refPage; 
    function refPage() 
    { 

     if(timeup == true) 
     { 


     if(refInterval == 1) 
     { 
      refInterval = 0; 
      location.reload(); 
     } 

     } 
     else 
     { 
      clearTimeout(awaytimer); 
     } 

     timeup = false; 

    } 

    window.onblur = timelyExit; 
    function timelyExit() 
    { 
     refInterval = 1; 

     // change this to trigger some kind of inactivity timer 
     awaytimer = setTimeout(function(){socket.send(JSON.stringify({ 
     uname: nme, 
     uid: id, 
     tag: "[bye]"      
     })); timeup=true; }, 900000); 


    } 


    window.onoffline = window.onunload = window.onbeforeunload = confirmExit; 
    function confirmExit() 
    { 
    socket.send(JSON.stringify({ 
     uname: nme, 
     uid: id, 
     tag: "[bye]" 

    })); 

    socket.close(); 
    } 


socket.onclose = function() { 

    openn = false; 


      //cant send server this message because already closed. 
    /* 
    socket.send(JSON.stringify({ 
     uname: nme, 
     uid: id, 
     tag: "[bye]" 

    })); 

    */ 

    socket.close(); 


}; 

コードについて

<?php 


require($_SERVER['DOCUMENT_ROOT'].'/var/www/html/vendor/autoload.php'); 

use Ratchet\Server\IoServer; 
use Ratchet\Http\HttpServer; 
use Ratchet\WebSocket\WsServer; 

$server = IoServer::factory(new HttpServer(new WsServer(new Chat)), 8080); 




$server->run(); 
?> 

コード)メソッドは、インターネット接続が終了すると起動しません。

私はまだ最初の解決策について行くことができる方法はありますか?

答えて

-3

免責事項:私は、巧みの共同創設者午前、単に優れたリアルタイム

これはまさにプラットフォームがあなたのために解決し、リアルタイム問題のタイプです。まず、ユーザーが存在するかどうかを検出するのにpresenceを使用できます。 Ablyを使用すると、ユーザーが突然切断された場合、15秒以内に通知され、明示的に切断された場合(クライアントによって)すぐに通知されます。

また、Ablyは、message continuity when clients become disconnected for short periodsの対処方法など、あなたが考える必要のある他の多くの問題を解決します。

ラチェットでこれを行う方法について私の答えは具体的に答えていないことを嬉しく思っていますが、実時間プラットフォームはこれらの問題を大規模かつ確実に解決するために構築されています。

+1

いいですが、私は現在、APIを支払う立場にいたいとは思っていません。また、1日あたり100接続に制限したいと思っていません。 – emjay

+0

aww cmon。ラチェットAPIを使用している人はいません。ラチェットAPIは、定期的にメッセージをすべてのクライアントに送信する方法を教えてくれますか? – emjay

0

切断クライアントを検出するためのこの最善の解決策は、イベントをベースとされるだろう、まったくクライアントをポーリングしません。このアプローチは、あなたの2番目の解決策であり、WebSocketメッセージの受け渡しの非同期性を巧みにモデル化しています。

ただし、特定のケースでは、いたずらなクライアントがソケットサーバーに接続解除を通知して、「ハングアップ」しているとは限りません。この場合、私はではなくにポーリングトリガを実装し、代わりにcronまたは他のタスクスケジューラ経由でトリガされた別のサーバ側クライアント経由でポーリングを開始し、ソケットに指示します接続されたすべてのクライアントをポーリングする要求を開始します。

サーバー側クライアントの構築の詳細については、this question of mineを参照してください。そのためにもいくつかの解決策を見つけることができました。


が切断メッセージを送信しを決定するために、私はわずかSplObjectStorageあなたが持っているRatchet\MessageComponentInterface実装の内部を使用してから行くのをお勧めし、代わりにシンプルな別のクラスの内部配列なので、このようなものを包むだろう:

ユーザーが最初に接続した直後にいくつかの時点で
class MyClientList 
{ 
    protected $clients = []; 

    public function addClient(Connection $conn) 
    { 
     $this->clients[$conn->resourceId] = [ 
      'connection' => $conn, 
     ]; 

     return $this; 
    } 

    public function removeClient(Connection $conn) 
    { 
     if(isset($this->clients[$conn->resourceId])) { 
      unset($this->clients[$conn->resourceId]); 
     } 

     return $this; 
    } 

    public function registerClient(ConnectionInterface $conn, array $userData) 
    { 
     if(isset($this->clients[$conn->resourceId])) { 
      $this->clients[$conn->resourceId] = array_merge(
       $this->clients[$conn->resourceId], 
       $userData 
      ); 
     } 

     return $this; 
    } 

    public function getClientData(ConnectionInterface $conn) 
    { 
     return isset($this->clients[$conn->resourceId]) ? 
      $this->clients[$conn->resourceId] : 
      null 
     ; 
    } 
} 

、あなたのクライアントは、サーバーへのソケットメッセージを送信し、今お使いの場合には、あなたがattemptinている(追加情報とクライアントの識別情報を登録するには、サーバーに指示する必要がありますgでunameuidのプロパティを識別します)。接続IDに対してインデックスを付けることで、この実装を使用して、最初の登録メッセージで送信した後にクライアントから発信されたすべてのメッセージのIDを指定できるようになります。

関連する問題