[ ホームページ ] [ 携帯用URL ]
将棋所のサポート掲示板
将棋所についての質問やバグ報告、USIエンジンの作成報告などに使用して下さい。

[ EZBBS.NET | 新規作成 | ランキング | オプション ]
iモード&(絵文字)、au対応!ケータイからも返信できる無料掲示板!
名前
 E-mail 
題名
内容
   タグ有効 改行有効 等幅フォント
URL
 



1077.(untitled)  
名前:Mizar    日付:2020/9/23(水) 14:10
WiMAXルータでの無通信タイムアウトによってTCPソケットの経路上でサイレントで切断された症状のように思われます。

クライアント側・サーバ側・もしくはその両方にて、TCP KeepAliveを有効にし、適切な生存確認の間隔を設定する方法を検討しても良いかと思います。

shogi-server を Linux上で動作させていた場合の例ですが、

https://ja.osdn.net/projects/shogi-server/scm/git/shogi-server/blobs/master/shogi-server
shogi-server:492 に記述がありますが、tcp_keepalive_timeなどの設定値を変更することが考えられます。
```
client.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true)
# Keepalive time can be set by /proc/sys/net/ipv4/tcp_keepalive_time
```

https://tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/

サーバ側の設定変更案)
tcp_keepalive_time を 7200 から 60 に変更
tcp_keepalive_intvl を 75 から 5 に変更
tcp_keepalive_probes は 9 のまま
(生存確認を60秒おきに行う、応答が無ければ5秒おきに再送、9連続で応答が無ければ接続を閉じる)

クライアント側(Windows)に関しては、レジストリキー HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Service\TCPIP\Parameters の KeepAliveTime のREG_DWORD値を短めに設定する、プログラム側でもTCPソケット接続作成時にKeepAliveを有効にする、等があるかもしれません。(詳細は未確認です)
https://docs.microsoft.com/ja-jp/windows/win32/winsock/so-keepalive



1079.Re: (untitled)
名前:Mizar    日付:2020/9/24(木) 1:11
https://docs.microsoft.com/ja-jp/windows/win32/api/winsock2/nf-winsock2-wsaioctl
https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/dd877220(v=vs.85)

http://hei.techblog.jp/archives/2223221.html
https://n1dalap.hatenablog.com/entry/2014/08/04/232057

恐らく、レジストリを弄らなくてもSocketを生成してからconnect()するまでの間に、設定値を記したtcp_keepalive構造体を用意してからWSAIoctl()でKeepAliveの設定値を変更して有効化出来るという話かと思います。


1081.Re: (untitled)
名前:Mizar    日付:2020/9/24(木) 10:56
お互いに無通信状態になった場合の疎通を確認できるよう、クライアント側とサーバ側の双方でTCP Keep-Aliveを有効にして、適切な確認の間隔を設定すべきだと思います。

TCP Keep-Aliveが動作しているかどうかについては、将棋所のデバッグコンソールを確認するだけでは限界がありますので、WireSharkなどのネットワークアナライザを使って確認した方が良いです。

サーバ側のみでTCP Keep-Aliveを有効にした際の実験例:
https://twitter.com/mizarjp/status/1308943548041949184

WireSharkの導入と解析例:
https://beginners-network.com/wireshark.html
https://beginners-network.com/wireshark_analyze.html


Windowsクライアント側における実装想定例:
```
#include <Mstcpip.h> // struct tcp_keepalive のため

SOCKET mySock;
tcp_keepalive tcpKeepalive;
DWORD dReturn;

tcpKeepalive.onoff = 1; // 非ゼロならオン
tcpKeepalive.keepalivetime = 60000; // KeepAliveを実施する無通信時間
(ミリ秒)
tcpKeepalive.keepaliveinterval = 1000; // KeepAliveの応答が無い場合の再送間隔(ミリ秒)
WSAIoctl(*mySock, SIO_KEEPALIVE_VALS, &tcpKeepalive, sizeof(tcpKeepalive), NULL, 0, &dReturn, NULL, NULL);
```


1083.Re: (untitled)
名前:Mizar    日付:2020/9/25(金) 15:16
TCP KeepAliveでは含まれるデータサイズが0バイト長のストリーム送信に該当します(余計な改行文字やコマンド文字列を送っても良いか、といった議論を行う必要がありません)。TCP KeepAlive自体は必須の実装ではないため、動作しない環境が存在する可能性もありますが、一般的なWindowsやLinux環境では動作するものですし、floodgateモードに限らずCSAモードでの接続などでも対応できそうなものですので、実装を検討してみてはいかがでしょうか。

参考) RFC1122 TRANSPORT LAYER -- TCP (October 1989) 日本語訳
https://jprs.jp/tech/material/rfc/RFC1122-ja.txt
```
4.2.3.6 TCP接続のキープアライブ

"キープアライブ"は広く受け入れられているものではないが、
実装者は、TCP実装にこの機能を組み込んでもよい(MAY)。
キープアライブが組み込まれている場合、アプリケーションは、
TCP接続ごとに機能を有効または無効にできなければならず(MUST)、
またデフォルトは無効でなければならない(MUST)。

キープアライブパケットは、一定期間内に接続に関するデータ
パケットも確認応答パケットも受信されなかった場合にのみ送信
されなければならない(MUST)。この期間は設定可能でなければ
ならず(MUST)、またデフォルトは2時間以上でなければならない
(MUST)。

データを含まないACKセグメントは、TCPによる確実な転送が
なされないことを思い出すことは極めて重要である。この理由に
より、キープアライブの仕組みが実装されている場合、いかなる
死活確認(probe)の失敗であっても、それを接続障害と解釈しては
ならない(MUST NOT)。

実装は、データを持たないキープアライブセグメントを送信すべき
である(SHOULD)。しかし、誤ったTCP実装との互換性のために、
1オクテットの不要データ(one garbage octet)を含めてキープ
アライブセグメントを送信するように設定可能であってもよい(MAY)。

【 議論 】
"キープアライブ"の仕組みは、それを行わないと接続が
アイドル状態になってしまう場合に、たとえ送信されるデータ
が無くても接続の対向側に対して死活確認を行うものである。
TCP仕様はキープアライブの仕組みを含まない。その理由は
以下の通りである。(1)一時的なインターネット障害の間に、
完璧に良好だった接続を壊してしまう可能性がある。(2)不要
な帯域を消費する可能性がある("誰も接続を使用していない
のなら、その接続がまだ良好かはどうでもよいのでは?")。
(3)パケット従量課金するインターネットパスではコストが
かさむかもしれない。

しかし、一部のTCP実装はキープアライブの仕組みを組み
込んできた。アイドル状態の接続がまだ有効であることを
確認するため、これらの実装は、対向側TCPから応答を引き出す
ように設計された死活確認セグメントを送信する。そのような
セグメントは、一般にSEG.SEQ=SND.NXT-1を含み、1オクテット
の不要データを含む場合もあれば含まない場合もある。
平穏な接続ではSND.NXT=RCV.NXTになるので、このSEG.SEQ
はウインドウの範囲外であることに注意せよ。従って、
死活確認は受信者に確認応答セグメントを返させ、それにより
接続がまだ生きていることを確認する。対向側がネットワーク
からの隔絶またはクラッシュにより接続を打ち切っていた場合、
確認応答の代わりにRSTを応答するだろう。

残念なことに、一部の作法を守らないTCP実装は、セグメントが
データを含まない限りSEG.SEQ=SND.NXT-1のセグメントの応答に
失敗する。代替手段として、実装は、対向側が不要データ
オクテットを含まないキープアライブパケットに正しく応答して
きたかを判定して対処することもできるかもしれない。

TCPキープアライブの仕組みは、ネットワーク障害中に
クライアントがクラッシュまたはアボートした場合、キープ
アライブを行わないと無期限にハングアップし、リソースを
不必要に消費してしまうようなサーバーアプリケーションに
おいてのみ起動されるべきである。
```


1084.Re: (untitled)
名前:Mizar    日付:2020/9/25(金) 15:57
TCP KeepAliveで問題になる可能性としては、今の所以下のような点が考えられます。

どの程度の無通信時間(tcp_keepalive_time)でKeepAliveを送信するべきか(TCP KeepAliveはデフォルトでは2時間以上)、またKeepAliveの応答が無かった場合の再送間隔(tcp_keepalive_intvl)と最大再送回数(tcp_keepalive_probes)はどの程度とするか。(頻度が過少であれば障害を検出しにくく、頻度が過大であればネットワークのコストがかさむ、最大最小回数が過少であれば正常な通信対戦が続行できる程度の軽度の障害で切断してしまう恐れがある)

TCP KeepAliveの有効化で問題が起きる(対応していない、バグを抱えている)ネットワーク機器(宅内・ネットワーク接続提供者・サーバ側等の、ルータ、モデム、ファイアウォールなど)が経路上に存在しないかどうか。通信元・通信先の環境は共に対応しているかどうか。


1085.Re: (untitled)
名前:Mizar    日付:2020/9/25(金) 16:53
Winsock2にてソケットごとにキープアライブの間隔を設定するコード例:
http://read.pudn.com/downloads79/ebook/301417/Chapter09/SIO_KEEPALIVE_VALS/alive.c__.htm


1087.Re: (untitled)
名前:将棋所の作者    日付:2020/9/26(土) 15:2
TCP KeepAliveを設定すると、接続が切れたときに受信スレッドで例外が発生するようなのですが、受信スレッドでの例外というのは他の原因で発生することもあり、再ログインのイベントとしては使うには扱いにくいところがあります。TCP KeepAliveにより切断自体を防げる可能性もありますが、それを確かめるには長時間のテストが必要です。
現在検討している、対局中にKeepAliveを送る方法であれば、例外が発生した時の再ログインも簡単なので、とりあえずそれでテストしようと思っています。他の方法でうまくいかなければTCP KeepAliveも検討したいと思います。

「1077.(untitled)」への返信

無料アクセス解析

アクセス解析の決定版!無料レンタルで最大100ページ解析!

   投稿KEY
   パスワード

EZBBS.NET produced by InsideWeb