PHP Websocket Detect如果发送聊天消息

时间:2016-09-09 11:10:46

标签: php ios websocket ratchet

我使用Ratchet Websocket Library在移动应用程序上聊天。

我使用了以下代码:发送/重发消息:

class Chat implements MessageComponentInterface {
    protected $clients;

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

    public function onOpen(ConnectionInterface $conn)
    {
        $this->clients->attach($conn);
        echo "New connection! ({$conn->resourceId})\n";
    }

    public function onMessage(ConnectionInterface $from, $msg)
    {

        foreach ($this->clients as $client) {
            if ($from !== $client) {

                $client->send($msg);
            }
        }
    }

    public function onClose(ConnectionInterface $conn)
    {

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

        echo "Connection {$conn->resourceId} has disconnected\n";
    }

    public function onError(ConnectionInterface $conn, \Exception $e)
    {
        echo "An error has occurred: {$e->getMessage()}\n";

        $conn->close();
    }
}

在iOS上,当用户进入聊天界面时,我会调用Connection Open来打开手机和网络之间的连接。但当我断开Wifi。在服务器上OnClose没有被调用。因此,服务器未收到有关当前连接断开连接的通知。当服务器向应用程序发送任何消息时,它不会被iOS应用程序接收。我想知道有没有办法在OnMessage函数中检测到$client->send($msg)实际上是否已被发送?

1 个答案:

答案 0 :(得分:1)

你必须记住的是WebSocket只是一个TCP套接字连接。这是一个可以在任何一端终止的有状态套接字。

  

连接终止阶段使用四次握手,连接的每一侧都独立终止。当端点希望停止其连接的一半时,它发送FIN数据包,另一端用ACK确认。因此,典型的拆除需要来自每个TCP端点的一对FIN和ACK段。

     

Source: Wikipedia - Transmission Control Protocol: 4.2 Connection Termination

因此有两种方法可以终止此套接字。

  1. 干净地任一端发送FIN数据包,另一端确认该请求,然后完成结束握手。
  2. 不那么干净一端被切断而不发送FIN数据包以完成结束握手。
  3. 在您的情况下,断开WiFi意味着服务器可能没有从客户端收到任何此类结束握手,并将保持TIME_WAIT状态以获得最大允许超时。在达到此超时之前,服务器不知道连接已丢失。除非服务器尝试向此客户端发送数据,否则将发生连接丢失错误,这也会发生超时,因为在确定数据包之前,数据包将在未经另一端确认的情况下多次发送客户肯定不见了。

    您无法通过onMessage回调检测到此问题,但是您可以通过onError回调方法检测到它。如果发生这种情况,服务器尝试将数据发送到客户端并失败,或者发生超时,则异常将从此回调冒泡到您的应用程序代码,您可以在其中捕获并适当地处理它。

    请记住,因为与客户端的不正常断开连接,在实际发生超时之前不会显示此异常。所以它不会立即发生,因为服务器不会立即知道它。