質問: Arduino特有の問題というより、TCP/IPを詳しく知らないため、対策が頭打ちです。 イーサシールドに互換のある、W5100やenc28j60といったボードを使っているのですが、時折、通信に不具合が起きるらしく、不具合へ対応するコードが書けずにいます。 対策として、watchdogで再起動するのですが、どうも、失敗があります。原因は、ルータのクライアント一覧にあるとだめらしく、5分ほど置いてから再起動すると大丈夫なのです。 ・arduino、httpでgetリクエストを投げる ・リクエスト処理が終わらず、8秒経つと、watchdogタイマで再起動 ・3時間程度、1日程度、数週間と、頻度はばらばらで停止 通常、成功するまで再起動を続けるので、例えば、ルータ側に問題が生じても、おおむね復旧しますが、駄目な場合があり、現地対応するのですが、Arduinoの電源再投入では復旧しません。 バッファロールータに光回線とよくある構成でインターネットへ接続するのですが、ルータの管理画面にて、クライアント一覧に名前がある間、再接続を受付けません。 5分ほど待つと一覧から消えるらしく、何もなかったかのようにすんなりつながりますが、キャッシュを上書きしたり、キャッシュの有効期限を短くするなりの方法がないかなと。 自身の経験として、有線接続でも、Windows端末は、OS上で接続を切断、再度、接続すれば、すぐ通信できます。TCP/IPの正しい切断手順が守られず、再接続時に失敗しているようです。 Arduino上で再現するには、何から勉強したら良いのか、どなたか、ヒントを教えて下さる方があればと質問します。リセット操作をスケッチで行うなどの方法がないでしょうか。
回答: TCP/IPの同一ポートへのbind()が失敗しているという事を想定して回答します。 アクティブクローズ(自身が先にclose)からのTIME_WAITによる2MLの影響で 120秒の間、同一ポートにbind()するする事が出来ません。 これに対する対策として、SO_REUSEADDRオプションを使用すれば同一ポートで bind()する事が出来ます。簡単に言うと120秒間また無くてもbind()が成功します。 もう一つの対策として、bind()で指定するポート番号を「0番」で指定すると TCPプロトコル側でランダムなポートを設定してくれます。 つまりTIME_WAIT状態のポートを避けることが出来るのでbind()が失敗しなくなります。 ただ、わざわざ0番ポートにbind()する必要はないので下記の手順で接続できるようになるのではないかと思います。 ■TCPクライアント接続手順 1.socket() 2.connect() ※ランダムポートでTCP接続される(クライアントの場合はbindの必要はない)