2015年12月21日月曜日

Ether ShieldのW5100をSTM8Sから動かしてみる (6)TCP死亡中

UDPとpingが通ったので、つぎはTCPを通そうと思うわけですが、、、謎のトラブルが発生しているところです.

読者の皆さんはすでにご存知かもですが、わたしはW5100を弄り始めて初めて知ったのですが、ネットとかLANとかEthernetというとTCP/IPなどという用語が連想され、ゆえにLANのプロトコル=TCPという認識しかありませんでした.
しかし、実際にはUDPやICMPといったプロトコルもあり、それらの方が通信が簡単なので勉強がてらUDPやICMPを実装してこれまで遊んできたわけでした.もっとも、ネットを飛び交っているプロトコルはTCPが90%を占めるらしいですが.

UDPやICMPが簡単である理由は、それらはpacketを送りっぱなしだからで、接続やエラー再送なんかしないので実装が簡単だというわけです.
ところがTCPは、先んじてマシンA-マシンBでネゴシエーションして接続を確立してからデータを送受信する、エラーがあったら再送する、などがあるので実装がめんどくさい.

それで実験です.
W5100をTCPモードで待ちうけ(サーバ 192.168.1.100)して、こちらのページを参考にしてクライアント(192.168.1.2)からチョイとTCP接続してチョイと"HELLO"を送信するようにして、W5100がTCPで動いた確認としたい.

 クライアントのrubyプログラム1
 #!/usr/bin/ruby
 require "socket"
 sock = TCPSocket.open("192.168.1.100", 12340)
 sock.write("HELLO")
 sock.close

ところが、W5100が"HELLO"を受信できません.これは困った.

packet monitor でサーバ(192.168.1.100)とクライアント(192.168.1.2)の間を飛び交うpacketを観測したのがこちら.
tshark -i 1 -f 'port 12340'
[NG]
  1 0.000000  192.168.1.2 -> 192.168.1.100 TCP [SYN] Len=0
  2 0.000183 192.168.1.100 -> 192.168.1.2  TCP [SYN, ACK] Len=0
  3 0.000229  192.168.1.2 -> 192.168.1.100 TCP [ACK] Len=0
  4 0.000333  192.168.1.2 -> 192.168.1.100 TCP [PSH, ACK] Len=5
  5 0.000380  192.168.1.2 -> 192.168.1.100 TCP [FIN, ACK] Len=0
  6 0.000801 192.168.1.100 -> 192.168.1.2  TCP [ACK] Len=0

SYNやACKなどのキーワードが飛び交っていて、TCPのネゴシエーションは正常っぽく見えます.4行目でLen=5となっているのは"HELLO"が5文字だからであって、データ伝送も正常っぽい.

けれど、W5100の内部の受信バッファには"HELLO"が入ってこない.つまり受信不能です.

W5100の内部ステータスをチェックすると、TCP接続確立の直後にSOCKET CLOSEになってしまっている.どうしてだろう???

-----
クライアントのrubyプログラムにdelayを挿入してみたら、W5100が"HELLO"を受信できるようになりました.socketをcloseする前にあるfor~end文がdelayです.

 クライアントのrubyプログラム2
 #!/usr/bin/ruby
 require "socket"
 sock = TCPSocket.open("192.168.1.100", 12340)
 sock.write("HELLO")
 for i in 0..10000 do
 end
 sock.close

クライアントがこれ↑ならW5100が正常動作するわけですから、飛び交うpacketの時刻がどれだけ変わったかに着眼してみます.tshark表示の2列目がpacketが飛んだ時刻(秒)です.

5行目のFINと書かれたpacketがSOCKET CLOSEの意味を持っています.そのpacketが飛んだ時刻は+2.397mSec後になっています.一方で動作不良なケースでは、5行目の時刻は+0.380mSec後と遥かにせわしなく動いています.
[OK]
  1 0.000000  192.168.1.2 -> 192.168.1.100 TCP [SYN] Len=0
  2 0.000183 192.168.1.100 -> 192.168.1.2  TCP [SYN, ACK] Len=0
  3 0.000227  192.168.1.2 -> 192.168.1.100 TCP [ACK] Len=0
  4 0.000333  192.168.1.2 -> 192.168.1.100 TCP [PSH, ACK] Len=5
  5 0.002397  192.168.1.2 -> 192.168.1.100 TCP [FIN, ACK] Len=0
  6 0.002558 192.168.1.100 -> 192.168.1.2  TCP [ACK] Len=0

というわけで、本日のトラブルはクライアントの速度にW5100が追いついてないと見える状況ですが、これってなにげにfuckな感じがしちゃっているところです.

追記1:
治ったわけではありませんが、内部状態をモニタするために各所に挿入してあったUARTへの送信命令を削除すると、不具合が軽減されました.やはりW5100の動作を妨げないのが吉であるらしいです.

追記2:
治ったわけではありませんが、rubyプログラム末尾のsock.closeを削除すると、正常に動作します.sock.closeを削除すると、close要求packetの送信時刻がわずかに遅延するのでW5100をcloseに叩き込む作用が遅延し、その結果正常動作に持ち込めていると推測します.

追記3:
治ったわけではありませんが、rubyプログラムをあきらめて、代わりにブラウザのchromeからW5100にTCP接続してみます.chromeのURLにこれを与えます.
http://192.168.1.100:12340
すると、chromeがW5100とのTCPネゴシエーションに成功し、chromeが送信したHTTPのメッセージをW5100が受信できました.rubyだと死ぬがchromeなら動くという微妙な情勢です.
 [TCP recv] reg BYTE=356(0164)  bufadrs=6800
 GET / HTTP/1.1
 Host: 192.168.1.100:12340
 Connection: keep-alive
 Accept: text/html,application/xht
rubyから受信できない不具合を治せる気がしないのと、実をいうとTCPの目的はHTTPサーバーを実装することなので、chromeとの通信が正常なら許そうと思ふ.

5へ   7へ

エイメン

=== STMのアフィリエイト始めました ===
STM32のwelcome-kitです
        
試用レポはいずれまた...

1 件のコメント:

  1. 前に書きましたっけ・・NTTの工事の後、時々接続できないとなったので、接続プロバイダにIP4アドレスを確認しました。
    自動設定を推奨しているとのことでアドレス変更を通知してなかったとのこと。(変えたなら言ってね・・なに合ってないと繋がりにくいだけ・・かえって良く繋がるとかは無いとか、ああややこし)
    ここで面白いのはプロバイダのカバー範囲で適当に振ってやっても接続できるのを確認、パスワードなどは確認しないみたい。
    更に無関係のアドレスでも接続できるのも確認。
    ひょっとして無料で接続できるのか?
    (例のアメリカのユニバーサルアドレスは使ってはいけないそうです)

    WIN7はLAN固定にすると自動的にWAN-DSN設定にしかできない、ここにIPアドレスを入れたら、ルータのIPアドレスより優先されるので、ルータの設定は関係ないし、PC側で自由に振れる・・変なの。

    返信削除