【问题标题】:How to maintain Channel API connection when internet is offline互联网离线时如何保持 Channel API 连接
【发布时间】:2013-12-06 03:52:53
【问题描述】:

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

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

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

谢谢。

【问题讨论】:

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


    【解决方案1】:

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

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

    而且,您还可以在服务器端跟踪连接,请参阅: 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;
      }]);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-14
      • 1970-01-01
      • 1970-01-01
      • 2020-12-23
      • 2019-04-28
      • 2019-12-25
      相关资源
      最近更新 更多