如何在Internet脱机时维护Channel API连接

时间:2013-12-06 03:52:54

标签: java google-app-engine channel-api

我正在使用Google AppEngine的Channel API。由于用户的网络连接,我有一些问题需要重新启动丢失的连接。当你松开互联网连接时,通道调用onError但它不会调用onClose。就JavaScript对象而言,通道套接字是打开的。

如何处理由于互联网问题导致的连接丢失?我想1)通过触发器关闭通道并重新打开它,当第一次与应用程序某处的通道无关的RPC成功(这表明互联网再次存在)或2)使用运行所有的计时器时间和ping服务器的网络状态(这是引入长轮询,以避免以这种方式消耗不需要的资源)。任何其他想法都会很棒。

观察: 当互联网连接失效时,会在增量间隔(10秒,20秒,40秒)内调用onError两次。一旦互联网连接恢复,频道就不会恢复连接。它停止工作,没有任何迹象表明它已经死了。

感谢。

1 个答案:

答案 0 :(得分:1)

当您看到javascript控制台时,可能会看到“400 Unknown SID Error”。 如果是这样,这是我的解决方法。这是AngularJS的服务模块,但请查看onerror回调。请尝试这种解决方法,让我知道它是否有效。

补充:我忽略了回答你的主要问题,但在我看来,很难确定你是否连接到互联网,除非实际ping了“互联网”。因此,您可能希望使用类似于以下代码的一些重试逻辑进行一些调整。在下面的示例中,我只重试了3次,但您可以通过一些后退来完成更多操作。但是,我认为处理此问题的最佳方法是,当应用程序使用重试最大计数时,您可以指示用户该应用程序丢失了连接,理想情况下显示按钮或重新连接到频道服务的链接。 / p>

并且,您还可以在服务器端跟踪连接,请参阅: https://developers.google.com/appengine/docs/java/channel/#Java_Tracking_client_connections_and_disconnections

app.factory('channelService', ['$http', '$rootScope', '$timeout',
  function($http, $rootScope, $timeout) {
    var service = {};
    var isConnectionAlive = false;
    var callbacks = new Array();
    var retryCount = 0;
    var MAX_RETRY_COUNT = 3;

    service.registerCallback = function(pattern, callback) {
      callbacks.push({pattern: pattern, func: callback});
    };

    service.messageCallback = function(message) {
      for (var i = 0; i < callbacks.length; i++) {
        var callback = callbacks[i];
        if (message.data.match(callback.pattern)) {
          $rootScope.$apply(function() {
            callback.func(message);
          });
        }
      }
    };

    service.channelTokenCallback = function(channelToken) {
      var channel = new goog.appengine.Channel(channelToken);
      service.socket = channel.open();
      isConnectionAlive = false;
      service.socket.onmessage = service.messageCallback;

      service.socket.onerror = function(error) {
        console.log('Detected an error on the channel.');
        console.log('Channel Error: ' + error.description + '.');
        console.log('Http Error Code: ' + error.code);
        isConnectionAlive = false;
        if (error.description == 'Invalid+token.' || error.description == 'Token+timed+out.') {
          console.log('It should be recovered with onclose handler.');
        } else {
          // In this case, we need to manually close the socket.
          // See also: https://code.google.com/p/googleappengine/issues/detail?id=4940
          console.log('Presumably it is "Unknown SID Error". Try closing the socket manually.');
          service.socket.close();
        }
      };

      service.socket.onclose = function() {
        isConnectionAlive = false;
        console.log('Reconnecting to a new channel');
        openNewChannel();
      };

      console.log('A channel was opened successfully. Will check the ping in 20 secs.');
      $timeout(checkConnection, 20000, false);
    };

    function openNewChannel(isRetry) {
      console.log('Retrieving a clientId.');
      if (isRetry) {
        retryCount++;
      } else {
        retryCount = 0;
      }
      $http.get('/rest/channel')
          .success(service.channelTokenCallback)
          .error(function(data, status) {
            console.log('Can not retrieve a clientId');
            if (status != 403 && retryCount <= MAX_RETRY_COUNT) {
              console.log('Retrying to obtain a client id')
              openNewChannel(true);
            }
          })
    }

    function pingCallback() {
      console.log('Got a ping from the server.');
      isConnectionAlive = true;
    }

    function checkConnection() {
      if (isConnectionAlive) {
        console.log('Connection is alive.');
        return;
      }
      if (service.socket == undefined) {
        console.log('will open a new connection in 1 sec');
        $timeout(openNewChannel, 1000, false);
        return;
      }
      // Ping didn't arrive
      // Assuming onclose handler automatically open a new channel.
      console.log('Not receiving a ping, closing the connection');
      service.socket.close();
    }

    service.registerCallback(/P/, pingCallback);
    openNewChannel();

    return service;
  }]);