[Q&A] peer.open後のネットワーク切断とスリープでの挙動について

1,298 views
Skip to first unread message

AIT Komukai

unread,
Aug 2, 2015, 1:21:01 AM8/2/15
to SkyWay Technical Forum
お世話になっております、小向です。

peer.open後にネットワークを切断し、一定時間放置すると
1、#PeerJS:  ERROR WS timed out
2、#PeerJS:  ERROR WS closed with code 1006
3、#PeerJS:  ERROR Error: Lost connection to server.
と最後にnetworkエラーが発生します。

しかし、
peer.open後にパソコンをスリープし、一定時間放置した後で復帰すると
1、#PeerJS:  ERROR WS timed out
2、#PeerJS:  ERROR WS closed with code 1006
の後にnetworkエラーは発生せずにpeer: openが自動的にコールされています。

当方としてはnetworkエラーになって欲しいのですが、
このような状況でnetworkエラーにする、もしくはpeer: openせずにcloseする方法はないでしょうか?

どうぞよろしくお願いいたします。

Yusuke NAKA

unread,
Aug 3, 2015, 9:52:11 AM8/3/15
to SkyWay Technical Forum
小向様

仲です。

こちらでも再現を試みてみましたが、以下の状況で、
peer.openが自動的にコールされるという状況が再現できませんでした。
「ERROR Error: Lost connection to server.」(networkエラー)は発火しないのは確認しました。
もしよろしければ、どのようなコードを書いているのか教えていただくことは可能でしょうか?
 

しかし、
peer.open後にパソコンをスリープし、一定時間放置した後で復帰すると
1、#PeerJS:  ERROR WS timed out
2、#PeerJS:  ERROR WS closed with code 1006
の後にnetworkエラーは発生せずにpeer: openが自動的にコールされています。


お手数おかけいたしますが、よろしくお願い致します。 

AIT Komukai

unread,
Aug 4, 2015, 7:23:47 AM8/4/15
to SkyWay Technical Forum
沖様
以下、当方で確実に再現するソースになります。
SkyWayキーを変更してご確認ください。

確認環境
 MacBook Pro (15-inch, Mid 2012)
 OSX Yosemite 10.10.4
 Chrome 44
 ※スリープ時間は5分から30分程度で試しております。

どうぞよろしくお願いいたします。


<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Expires" content="-1">
<title></title>
</head>
<body>
<button type="button" class="start">スタート</button>
<button type="button" class="status">ステータス</button>
<script src="https://skyway.io/dist/0.3/peer.js"></script>
<script>
var SkyWayParams = {
config : {
skyWay : {
key : 'ここをSkyWayキーに置き換えてください',
turn : true,
config : {
'iceServers': [{'url': 'stun:stun.skyway.io:3478'}]
},
debug : 3
},
},
peer : null,
};
var PeerUtils = {
destroyPeer: function()
{
console.log('['+Date.now()+'] [PeerUtils] destroyPeer:');
if (SkyWayParams.peer === null)
{
console.log('['+Date.now()+']             peer is null');
return true;
}

if (SkyWayParams.peer.destroyed === false)
{
SkyWayParams.peer.destroy();
}
return false;
},

clearPeer: function()
{
console.log('['+Date.now()+'] [PeerUtils] clearPeer:');
if (SkyWayParams.peer === null)
{
console.log('['+Date.now()+']             peer is null');
return;
}
SkyWayParams.peer.off('open');
SkyWayParams.peer.off('error');
SkyWayParams.peer = null;
},

initPeer: function()
{
console.log('['+Date.now()+'] [PeerUtils] initPeer:');
if (PeerUtils.destroyPeer() === false)
return;

PeerUtils.clearPeer();
SkyWayParams.peer = new Peer( SkyWayParams.config.skyWay );
SkyWayParams.peer.on('open', PeerUtils.peerEvents.open);
SkyWayParams.peer.on('close', PeerUtils.peerEvents.close);
SkyWayParams.peer.on('error', PeerUtils.peerEvents.error);
},


peerEvents:
{
open: function(id)
{
console.log('['+Date.now()+'] [PeerUtils] peer.open: ', SkyWayParams.peer.id);
PeerUtils.peerStatus();
},

close: function()
{
console.log('['+Date.now()+'] [PeerUtils] peer.close: ', SkyWayParams.peer.id);
PeerUtils.peerStatus();
PeerUtils.clearPeer();
},

error: function(error)
{
console.log('['+Date.now()+'] [PeerUtils] peer.error: ', SkyWayParams.peer.id);
console.log('['+Date.now()+']                   type: ', error.type);
console.log('['+Date.now()+']                message: ', error.message);
PeerUtils.peerStatus();
if (error.type !== 'peer-unavailable')
PeerUtils.clearPeer();
}
},


peerStatus: function()
{
console.log('['+Date.now()+'] [PeerUtils] status:');
console.log('['+Date.now()+'] >>>>>>>>>>>>>>>>>>>');
if (SkyWayParams.peer)
{
console.log('['+Date.now()+']            id: ', SkyWayParams.peer.id);
console.log('['+Date.now()+']  disconnected: ', SkyWayParams.peer.disconnected);
console.log('['+Date.now()+']     destroyed: ', SkyWayParams.peer.destroyed);
}
else
{
console.log('['+Date.now()+']  peer is null');
}
console.log('['+Date.now()+'] <<<<<<<<<<<<<<<<<<<');
}
};


//------------------------------------
// UI操作
$(function(){
$('.status').on('click', function(){
PeerUtils.peerStatus();
});

$('.start').on('click', function(){
PeerUtils.initPeer();
});
});
</script>
</body>
</html>





2015年8月3日月曜日 22時52分11秒 UTC+9 Yusuke NAKA:

Yusuke NAKA

unread,
Aug 6, 2015, 1:48:55 AM8/6/15
to SkyWay Technical Forum
小向様

仲です。
情報有り難うございます。
原因がわかりました。

まず、SkyWayのサーバとの接続の仕組みを少しお話します。
SkyWayでは、WSによりサーバと常時接続しサービスを提供しています。
また、WSによる接続が何らかの理由で切れた場合は、自動的にXHR(ロングポーリング)に切り替えてサービスを継続提供いたします。

手動でネットワークを切断した場合は、以下の様なフローでネットワークエラーが発生します。

1,new Peer()でサーバとのWSを開始
2,手動でネットワークを切断
3,クライアントとSkyWayのサーバはWSの切断を検知
4,クライアントはXHRで再接続を試みる
5,クライアントはネットワークが切断されているため再接続できない
6,「ERROR Error: Lost connection to server.」が発生


スリープにした場合は、以下の様なフローになります。

1,new Peer()でサーバとのWSを開始
2,PCがスリープモードになる
3,SkyWayのサーバはWSが切れたのでクライアントがいなくなったと判断する(クライアントはスリープ中なので処理が進まない)
4,PCを復旧する
5,クライアントはWSの切断を検知
6,ライアントは XHRで再接続を試みる
7,ネットワークは疎通しているため、XHRでの再接続に成功し、以後XHRでサービスを継続


結論としてましては、後者はネットワーク的には切れておらず、正常にサービスが出来る状態ということになります。

以上、ご確認お願い致します。


2015年8月4日火曜日 20時23分47秒 UTC+9 AIT Komukai:

AIT Komukai

unread,
Aug 6, 2015, 2:50:33 AM8/6/15
to SkyWay Technical Forum
仲様
お世話になっております、小向です。

ご確認いただきありがとうございます。
挙動の原因について理解することができました。

そこで最初に戻りますが、
XHRによる自動再接続の許可・拒否をクライアント側で制御する方法はないでしょうか?

それと前の回答で、
「peer.openが自動的にコールされるという状況が再現できませんでした。」とありましたが、
7,からのpeer.openが発生しなかった理由について教えていただけないでしょうか?

どうぞよろしくお願いいたします。



2015年8月6日木曜日 14時48分55秒 UTC+9 Yusuke NAKA:

Yusuke NAKA

unread,
Aug 6, 2015, 3:19:56 AM8/6/15
to SkyWay Technical Forum
小向様

仲です。

 
そこで最初に戻りますが、
XHRによる自動再接続の許可・拒否をクライアント側で制御する方法はないでしょうか?

単純にXHRを無効にしたい場合は、
peer.jsの1306行目にある  this._startXhrStream(); をコメントアウトすればWSのみになります。
必要に応じてクライアントからON/OFFする仕組みは提供しておりません。

 

それと前の回答で、
「peer.openが自動的にコールされるという状況が再現できませんでした。」とありましたが、
7,からのpeer.openが発生しなかった理由について教えていただけないでしょうか?

どうぞよろしくお願いいたします。



すみません、こちらですが再度テストをするとXHRフォールバックが動いておりました。
検証に利用したテストアプリでは、peer.openが発生した際のログを出力しておらず、また、
XHRフォールバックの可能性を全く考えていなかったため、そのようにコメントしてしまいました。
お手数おかけ致しました。

AIT Komukai

unread,
Aug 6, 2015, 5:07:48 AM8/6/15
to SkyWay Technical Forum
仲様
ご返答ありがとうございます、小向です。

初めてソースを覗きましたが、
1356行も同様にコメントアウトした方が良さそうですね。

再現テストの件、他に問題がなく良かったです。

ありがとうございました。


2015年8月6日木曜日 16時19分56秒 UTC+9 Yusuke NAKA:

Yusuke Naka

unread,
Aug 6, 2015, 6:08:32 AM8/6/15
to skyw...@googlegroups.com
小向様

仲です。


初めてソースを覗きましたが、
1356行も同様にコメントアウトした方が良さそうですね。


1306行目は初回接続にXHRを使うか使わないかに効いてきます。
SkyWayでは、new Peer()後、WSとXHRを同時に張った上で、WS側で疎通できた場合はWSで以後通信し、出来なかった場合はXHRで以後通信します。
1356行目はXHRフォールバックを行うかどうかにかかってきます。

今回の場合は、仰るとおり、1306行目と1356行目を両方コメントアウトしなければ意味がありませんね。
失礼致しました。

尚、WSのみにするデメリットですが、WSが通らない環境では利用できなくなることと、
peer.jsバージョンアップ時には手動で差し換えて頂く必要が出てきます。


よろしくお願いいたします。


 

--
このメールは Google グループのグループ「SkyWay Technical Forum」に登録しているユーザーに送られています。
このグループから退会し、グループからのメールの配信を停止するには skywayjs+u...@googlegroups.com にメールを送信してください。
このディスカッションをウェブ上で閲覧するには https://groups.google.com/d/msgid/skywayjs/cdaf7110-fd4d-4006-bfd4-edbbf87e0a9d%40googlegroups.com にアクセスしてください。
その他のオプションについては https://groups.google.com/d/optout にアクセスしてください。



--
仲 裕介(Yusuke NAKA)

AIT Komukai

unread,
Aug 6, 2015, 8:37:10 AM8/6/15
to SkyWay Technical Forum
仲様
お世話になっております、小向です。

WSが通らない環境とはどのような環境を示しているのでしょうか?
未対応ブラウザで利用できなくなるという点しか思い当たらないので
他にございましたらご教授いただけないでしょうか?

お手数ですが、よろしくお願いいたします。


2015年8月6日木曜日 19時08分32秒 UTC+9 Yusuke NAKA:

You Kinjoh

unread,
Aug 6, 2015, 5:31:15 PM8/6/15
to skyw...@googlegroups.com
小向様

金城です。

主要なブラウザのうち
WebRTCに対応しているものは全て
WebSocketに対応しています。

しかし、ネットワーク等が
WebSocketに対応していない場合があります。

いくつか例を挙げます。

WebSocketを使うためには
HTTP1.1のSwitching Protocolに対応している必要がありますが、
途中のProxyがHTTP1.0にしか対応していない場合、
WebSocketは使えません。

また、WebSocketは通信が阻害されないために
HTTPを模してはいるのですが
完全ではありません。
このため、クライアントにインストールされた
セキュリティソフトや
WAF等が"異常な通信"と判断して
接続を切断することがあります。

WebSocketが使える割合は
(古い情報になってしまいますが)
http://www.ietf.org/mail-archive/web/tls/current/msg05593.html
を見ていただけると良いかと思います。

# 手前味噌ですが
# http://www.slideshare.net/You_Kinjoh/fundamentals-and-applicationsofhtml5thirdedition
# も参考になるかと思います。

このため、WebSocketを使うためのライブラリは
XHR(Ajax)にフォールバックするための仕組みを
用意していることがあります。
(有名どころではnode.jsのsocket.ioがあります。)
peer.jsもフォールバックのために
WebSocketだけでなくXHRで通信を試みます。

XHRを使わないようにすると、
シグナリング(呼制御)をWebSocketのみに頼ることになり、
WebSocketが使えない環境下ではフォールバックが働かず、
結果的にWebRTCによる
通信の確立ができなくなります。



2015年8月6日 21:37 AIT Komukai <ai.tac...@gmail.com>:
> https://groups.google.com/d/msgid/skywayjs/c6534bea-a76c-4f5c-b554-1373b00cafb0%40googlegroups.com

AIT Komukai

unread,
Aug 7, 2015, 5:10:14 AM8/7/15
to SkyWay Technical Forum
金城様
ご返答ありがとうございます、小向です。

詳しい説明・資料のご提供について感謝いたします。
早速330ページ拝読しました。
イノベーションは現在と未来を捉えがちですが、
良いイノベーションは過去から学べるという感じが目から鱗でした。

---

XHRを排除する方法はデメリットが大きいのでそのまま使用するとしまして、
WSからXHRへ切り替わる条件に経過時間を設定しました。
(一定時間内の切断であればXHRへ移行し、それを越えていれば場合はnetworkエラー)

ただしこのままではXHRによる再接続毎にpeer.openが発生するので、
アプリ側で古いピアIdを確保しておきpeer.open時にピアIdチェックで処理を分けるようにしました。
これでスリープからの復帰時に、
networkエラーにする、もしくはpeer: openせずにcloseすることが可能かなと思っています。

ちなみに、
XHRからWSへ復帰?することはないのですね。
PCならスリープから復帰してリロードするまではXHRのみとなり、
スマホも同様にXHRのみになってしまい予期せず通信コストが増える状況もあり得ると考えておく必要があると。

---
peer.jsの変更箇所を一応貼り付けておきます。
問題が生じるようでしたらご指摘いただければ幸いです。

// Fall back to XHR if WS closes
this._socket.onclose = function(msg) {
  util.error("WS closed with code "+msg.code);
  var elapsedTimeout = (+new Date) - self._elapsedTime;
  if(!self.disconnected && elapsedTimeout < 180000) {
    self._startXhrStream();
  } else if (!self.disconnected) {
    self.emit('disconnected');
  }
}

Socket.prototype._setWSTimeout = function(){
  this._elapsedTime = +new Date;
  var self = this;
  this._wsTimeout = setTimeout(function(){
      if(self._wsOpen()){
          self._socket.close();
          util.error('WS timed out');
      }
  }, 45000)
}


どうぞよろしくお願い致します。



2015年8月7日金曜日 6時31分15秒 UTC+9 You Kinjoh:

You Kinjoh

unread,
Aug 9, 2015, 2:17:42 PM8/9/15
to skyw...@googlegroups.com
小向様

金城です。

> イノベーションは現在と未来を捉えがちですが、
> 良いイノベーションは過去から学べるという感じが目から鱗でした。

すいません。
スライドを指定したリンクを貼るつもりが
ミスしてしまいました...。

http://www.slideshare.net/You_Kinjoh/fundamentals-and-applicationsofhtml5thirdedition/200

宣伝ぽくなってしまいすいません。

> ちなみに、
> XHRからWSへ復帰?することはないのですね。

これは確認したことがないです。
多分、コードを追ってみる必要があるかと思います。




2015年8月7日 18:10 AIT Komukai <ai.tac...@gmail.com>:
> https://groups.google.com/d/msgid/skywayjs/32bd2854-048d-43d0-a0a1-1c93ba7a44e8%40googlegroups.com

Yusuke Naka

unread,
Aug 9, 2015, 7:37:51 PM8/9/15
to skyw...@googlegroups.com
小向様 金城様

仲です。
コメント、フォローありがとうございます。


> ちなみに、
> XHRからWSへ復帰?することはないのですね。

これは確認したことがないです。
多分、コードを追ってみる必要があるかと思います。
 
一度XHRにフォールバックすると、WSにアップグレードされることはありません。

小向様の対応を拝見致しました。(動作確認までは実施できてませんが)


> XHRを排除する方法はデメリットが大きいのでそのまま使用するとしまして、
> WSからXHRへ切り替わる条件に経過時間を設定しました。
> (一定時間内の切断であればXHRへ移行し、それを越えていれば場合はnetworkエラー)
>

直前のサーバとのPING/PONGから180秒以上経過していれば(スリープ等で放置された場合等)強制クローズということですよね?
問題無いと思います。

 
> ただしこのままではXHRによる再接続毎にpeer.openが発生するので、
> アプリ側で古いピアIdを確保しておきpeer.open時にピアIdチェックで処理を分けるようにしました。
> これでスリープからの復帰時に、
> networkエラーにする、もしくはpeer: openせずにcloseすることが可能かなと思っています。

すみません、この機能の意図がよく理解できなかったのですが、
peer.open時に前回と同じピアidで接続しようとした場合は、エラーにするということでしょうか?
この条件だと、全てのXHRフォールバックがエラーの対象になってしまいそうですが、どうでしょうか?

もっと単純に考えると、peer.jsの1356行目のみをコメントアウトするのはどうでしょうか?
そうすると、一度WSでつながってしまったら、XHRにはフォールバックしません。

見当違いなことを言ってましたら、ご指摘下さい。

このメールは Google グループのグループ「SkyWay Technical Forum」の登録者に送られています。
このグループから退会し、グループからのメールの配信を停止するには skywayjs+u...@googlegroups.com にメールを送信してください。
このディスカッションをウェブ上で閲覧するには、https://groups.google.com/d/msgid/skywayjs/CABGp01zhWVQ_zvnhmiPiRznKs4gxU1NLXBGfs4QxbDnbM-hupg%40mail.gmail.com にアクセスしてください。
その他のオプションについては、https://groups.google.com/d/optout にアクセスしてください。



--
仲 裕介(Yusuke NAKA)

AIT Komukai

unread,
Aug 10, 2015, 2:11:24 AM8/10/15
to SkyWay Technical Forum
金城様、仲様
ご返答ありがとうございます、小向です。

金城様
全ページ通して良い資料でしたので逆にスライド指定でなく良かったです。


仲様
すみません、情報不足でした。
これまでpeer.open内でアプリ側の初期化を行っていましたが、
peer.openがコールされるタイミングが「WS接続された時」「XHR接続された時」の複数回あることを想定していなかったので、
2度目以降のpeer.openで初期化をしないよう条件分岐できればという意図でこの機能を追加しました。
(ピアId比較というよりフラグチェック)

また、
金城様からご指摘を受けましたWSの利用できない環境を考慮しますと
WSからXHRへのフォールバックは必要だと思いましたので1356行目をコメントアウトする方法は取りやめました。
しかし、スリープからの復帰によるアプリへの影響を制御するため1356行目に対して時間制限を追加してみた所です。


こちらで確認できたスリープによる挙動を共有しておきます。
 1、WS接続中にスリープして復帰した時
   WSがタイムアウトし、WSはクローズされてXHRへフォールバックする。
   XHRがタイムアウトする前にネット接続が再開されるとpeer.openがコールされる。(peer.idは同一)
   ネット不通だとpeer.error(networkエラー)がコールされる。

 2、XHR接続中にスリープして復帰した時
   XHRがタイムアウトし、peer.error(networkエラー)がコールされる。


誤りなど御座いましたらご指摘ください。
どうぞよろしくお願い致します。


2015年8月10日月曜日 8時37分51秒 UTC+9 Yusuke NAKA:

Yusuke NAKA

unread,
Aug 10, 2015, 8:57:59 PM8/10/15
to SkyWay Technical Forum
小向様

仲です。


これまでpeer.open内でアプリ側の初期化を行っていましたが、
peer.openがコールされるタイミングが「WS接続された時」「XHR接続された時」の複数回あることを想定していなかったので、
2度目以降のpeer.openで初期化をしないよう条件分岐できればという意図でこの機能を追加しました。
(ピアId比較というよりフラグチェック)

なるほど、理解しました。
ありがとうございます。

 

また、
金城様からご指摘を受けましたWSの利用できない環境を考慮しますと
WSからXHRへのフォールバックは必要だと思いましたので1356行目をコメントアウトする方法は取りやめました。
しかし、スリープからの復帰によるアプリへの影響を制御するため1356行目に対して時間制限を追加してみた所です。


有難うございます。
繰り返しになりますが、SkyWayでは最初にWSとXHRを両方はりにいき、WSが接続できなければXHRで通信を開始、WSが接続できればWSで通信を開始します。(1306行目の処理)
1356行目は、WSで通信が可能な環境でWSで通信を開始した後に、何らかの理由でWSが切断された場合に、XHRにフォールバックし通信を継続します。
今回、小向様が前者の場合に加えて後者の場合も考慮したいのであれば、仰るとおりの実装で問題ありません。
念のための確認でした。


こちらで確認できたスリープによる挙動を共有しておきます。
 1、WS接続中にスリープして復帰した時
   WSがタイムアウトし、WSはクローズされてXHRへフォールバックする。
   XHRがタイムアウトする前にネット接続が再開されるとpeer.openがコールされる。(peer.idは同一)
   ネット不通だとpeer.error(networkエラー)がコールされる。

 2、XHR接続中にスリープして復帰した時
   XHRがタイムアウトし、peer.error(networkエラー)がコールされる。


共有有難うございます。
挙動については、認識あっております。

AIT Komukai

unread,
Aug 10, 2015, 9:14:43 PM8/10/15
to SkyWay Technical Forum
仲様
お世話になっております、小向です。

問題がないようで良かったです。
これで本件が解決されました。

ありがとうございました。


2015年8月11日火曜日 9時57分59秒 UTC+9 Yusuke NAKA:
Reply all
Reply to author
Forward
0 new messages