WebSocket服务端开发(八)-WebSocketServer类错误处理

本文介绍WebSocketServer类错误处理相关方法。

错误信息显示

  //获取最后一次socket的错误码
  function getLastErrCode($socketId = null) {
    if (is_null($socketId)) {
      $socket = $this->serverSocket;
    } else {
      $socket = $this->socketListMap[$socketId]['socket'];
    }
    return socket_last_error($socket);
  }

  //通过错误码查找错误详情
  function getLastErrMsg($socketId = null, $errCode = null) {
    if (!is_numeric($errCode)) {
      $errCode = $this->getLastErrCode($socketId);
    }
    return '[' . $errCode . ']' . socket_strerror($errCode) . "\n";
  }

当客户端直接断开连接时(没有发送关闭帧),Windows下会出现socket错误10053,此时服务器可以直接断开此连接。在Linux服务器下,测试发现如果客户端断开连接,并不会出现10053错误(可能是服务器环境的问题),这时如果再收到连接会发现,已经断开的连接会造成死循环:
socket_select选中了断开的连接,然后从socket中读数据,Windows下调用socket_recv会返回false,而Linux下不会报错,这样会导致该连接不会从连接池中移除,然后会在下一次循环连接池时继续被选中,不停的循环。
这里解决方法是,对于有10053错误的,直接断开连接,不会出现任何问题。在接收数据后,如果数据长度大于0,则置该连接的errorCnt为0,否则errorCnt加一。判断errorCnt是否大于3次,如果大于3次,则断开该socket连接。也就是说,如果连续收到3次空内容的数据,就会断开连接。最后使用健康检查防止某些情况下没有移除连接的问题。

注意:该类只处理10053的socket错误,其他类型没有实现,可以通过覆盖onerror自定义自己的错误处理方式。

WebSocket服务端开发(七)-WebSocketServer类健康检查函数

本文介绍WebSocketServer类健康检查函数。

函数实现如下:

  function healthCheck() {
    //获取当前时间
    $now = time();

    //记录最后健康检查时间
    $this->lastHealthCheck = $now;

    //初始化不健康的连接列表
    $unhealthyList = array();

    //循环连接池
    foreach ($this->socketListMap as $socketId => $session) {
      //找出最后通信时间超过超时时间(目前超时时间与健康检查时间相同)
      if ($now - $session['lastCommuicate'] > $this->healthCheckInterval) {
        array_push($unhealthyList, $socketId);
      }
    }
    if ($this->debug) {
      echo 'Unhealthy socket:' . implode(',', $unhealthyList) . "\n";
    }

    //健康检查回调,默认的行为是直接断开连接
    //可以根据自己的需求改进,如发送ping帧探测等,如果仍无响应再断开连接
    $this->onafterhealthcheck($unhealthyList);
  }

注意:由于该类只是简单的实现了WebSocket协议,没有使用多线程处理,故健康检查只有在处理完一次连接后才有可能执行。如果设置健康检查时间间隔为10分钟,10分钟内收到任何数据,那么也不会进行健康检查,直到收到一个连接后才会进行健康检查。
收发数据都会更新最后通信时间的值,如果希望只在服务器收到信息时更新最后通信时间,可以在recv和send函数中修改。
建议定时从服务器发送心跳包以维持连接。