YMODEM受信中に通信が一時停止すると復帰できない
Tera Termの実装を確認しました。下記のようになっています。
・1バイト受信する度に、10秒タイマを仕掛ける。 ・タイムアウトすると、'C'を送り、SOHからやり直し。
すなわち、Tera Termでは受信シーケンスが途中で、一度でも失敗すると、ブロックの最初から 受信されることを期待しています。 'C'をNAK(0x15)に変えるのは簡単なのですが、それだけではダメなような気がします。
もう少し修正のポイントを教えてもらえるでしょうか?
ソースコードを見られる場合は、teraterm\ttpfile\ymodem.c の YReadPacket() あたりです。
早速のご確認、ありがとうございます。
YMODEMのシーケンスを解説しているサイトはいくつかありますが、 今回の症状については、次のサイトを参考にしています。
http://www.st.rim.or.jp/~phinloda/proto2.html
このサイトの解説では、次のような記述がありました。引用部分が多くて申し訳ありません。
2.2 YMODEM 2.2.3 転送手順 (中略) ファイル名が送信された後のデータ転送手順はXMODEMと同様である。
2.1.1 XMODEM の手順 (中略) 送信側は、ACKを受け取った場合には、次のブロックを送信する。 NAKを受け取った場合には、今送ったブロックをもう一度送信する。 (中略) 受信側でエラーと判断できる場合としては、以下のものが考えられる。 1. シーケンス番号とシーケンス番号の補数の和が255にならなかった場合。 この場合はいずれかが正しくないのであるが、 どちらが正しいともいえないのだからNAKを返送して再度ブロックを送ってもらうことになる。 2. 既に正常に受信したブロックと同じシーケンス番号のブロックが送られて来た場合。 例えばACKが途中で化けて送信側で認識されなかった場合にこのようになる。 ブロックは既に受信しているのだから、二度目に受け取ったブロックは無視してACKを送信すれば、 送信側は次のブロックを送ってくるはずである。 3. 次に受信すべきブロックが受け取れず、さらに先のブロックが送られて来た場合。 途中のブロックを受け取り損ねた場合である。このエラーの場合には、XMODEMは処理を続行することができない。 受信側は処理を中断するために、CANを続けて2回送信する。 4. データが送られてこない場合。回線の事情で、途中でデータが消失した場合には、 いくら待ってもデータが送られてこないはずである。10秒待っても期待したデータが到着しない場合には、 NAKを送り、再度の送信を促す。さらにデータが送られてこない場合には、10回までこれを繰り返す。 (中略) 送信側でエラーと判断できる場合としては、受信側からACKもNAKも戻ってこない場合が考えられる。 10秒待ってもACK、NAK、CANのいずれも戻ってこなかった場合には、送信側はNAKを受け取ったとみなして、 前回送ったブロックを再度送信する。
今回の症状は、Tera Termにとっては上記「4.」に該当すると思われます。
私はこの場合、
TeraTerm デバイス (受信側) (送信側) <--ブロックn-- 途中で 途切れて いると認識 10秒経過 -----NAK-----> <--ブロックn-- 再送 -----ACK-----> <-ブロックn+1-- : :
となることを期待しています。
なお、Tera Termの現状の振る舞いは、上記サイトの
2.1.1 XMODEM の手順 まず、XMODEMによるファイル転送を行うことが決まれば、送信側は受信側からNAKが送られてくるのを1分間待つ。 送信側は、これが送られてくるまで待つことになるが、NAKまたはCAN以外のキャラクタは全て無視する。 CANは、XMODEMの処理を中断するための指示であり、これを受け取れば送信側は即時処理を中断する。 送信側はNAKを受け取ると、ただちに最初のブロックを送信し始める。 受信側はNAKを送ると、最初のブロックが到着することを期待して待っている。の第二パラグラフの記述に近いと思われます。
しかしこれは前後の文脈を見ると、ブロック1の前のNAK(=XMODEMの開始)に関する記述だと思われますが、如何でしょうか。
ご確認よろしくお願いします。
NAK を送るのは、1つのブロックを送信後、次のブロックが来るまでの時間がタイムアウトした 場合でよいのでしょうか?
そのタイムアウト処理において、'C'の代わりに NAK を送るようにした修正を行ってみました。 下記にアーカイブを置いたので、試してみてもらえますか?
http://ttssh2.sourceforge.jp/snapshot/ymodem_snapshot-20120720.zip
迅速なご対応ありがとうございました。
yutakaponさんのご質問に回答しますと、
「NAKを送るのは、1つのブロックを受信後、次のブロックが来るまでの時間がタイムアウトした場合」
でよいと考えています。
teraterm-4_74/teraterm/ttpfile/ymodem.cの466行目とteraterm-4_74/teraterm/ttpfile/xmodem.cの346行目を比較してみても、そう見えます。
早速試したいのですが、自宅にはテスト環境がないため 検査結果の報告は週明けとさせてください。
申し訳ありませんが、今しばらくお待ち下さい。
yutakaponさん、お待たせいたしました。 動作確認を終えました。
ymodem_snapshot-20120720.zipを使って動作確認した結果、 通信が一時停止しても、再送シーケンスを経て転送を完了することができました。
また、ファイルの内容も正常でした。
症状は解消し、他にも問題は見当たらないと思います。
正式版TeraTermへの適用をよろしくお願いします。
テストどうもありがとうございました。 先ほど、修正コードをコミットしました。次のリリース(4.75)に含まれます。
ありがとうございました。次のリリースを楽しみにしています。
WindowsXP SP3(32bit)上で、Tera Term V4.74を利用しています。
シリアルポートで接続したデバイスから、PCにファイルを送信する手段として、Tera TermのYMODEM受信を利用しています。
Tera TermでYMODEM受信をしている最中に、PCの処理が追いつかないことによってTera Term側がブロックを正しく認識できず、ACKを返さないことがあります。
この状況を、以後「通信中断」と記述します。
通信中断が発生すると、次のような症状が現れます。
結果として、YMODEM受信を中止せざるを得なくなります。
WindowsXPに同梱のハイパーターミナルを利用している場合は、通信中断発生後、ハイパーターミナルがNAKを送信するため、それを以ってブロック再送が正しく処理でき、ファイル転送を継続することができます。
しかし、ハイパーターミナルはWindowsVista以降に搭載されていないため、今後も利用し続けることは難しいと考えています。
Tera Termでも、通信中断発生時にNAKを送信するよう変更していただけないでしょうか。
また、そのような対応ができない場合は、通信中断が発生した状況でYMODEM受信を継続する通信シーケンスを教えていただけないでしょうか。