uIP TCP/IPについて

先ごろ(だいぶ前ですが)ルネサスサイトから uIP TCP/IP Protocol Stack Demostration Document number:R01AN0169EU0100 Ver 1.01 NOTEs: * The demostration directory structure is explained in the application note. * This application note supports RX62N and the demostration project runs on RSK+RX62N. UIPのサンプルを入手しましてSH7670へ移植しました、その結果とても良好な結果を得ましたので報告します 自前のソースでTCP/IPを実装して稼動させていましたがよく応答ができなくなったりしていました いろいろな遷移状態でわけがわからないような(たぶんプロトコルが十分でない)遷移もありました UIPにすると必ず応答して、応答不良などまだ経験がありません、 ただこのUIP長い(大きい)データ転送には弱いんです、”どうしてこんなに時間がかかるの”というぐらい なにか説明ではACKが200mセコンドウェイト方式を採用しているからだとか これの速度はもっと速くはならないものでしょうか? IWIPなど聞きますが、UIPと比べてどうなのでしょうか、IWIPのほうがいいのでしょうか?
  • R_httpd();とhttp_callbackを手当てしてやってみると、

    void R_httpd(void)でcase HTTPD_CLOSED:の

    if(ercd != E_WBLK){でwhile (1);にはまります

    なにが足りないのかな?

    そこだけ違うCPUに抜き出してやっているので

    マニュアル等は詳しいものはありませんでした。

  • もしかしたら、リアルタイムOS用のブロッキングコール用のソース?

    ちょっと調べてみます

  • とりあえず、while (1);をreturn;にしてやりました、


  • IKUZOさん

    こんにちは、シェルティです。

    下記回答します。

    > R_httpd();とhttp_callbackだけを手当てしてやればよいのでしょうか?DNSも含めないといけないのでしょうか?

    手当はもう少し必要です。DNSは不要です。

    手当①:config_tcpudp.c の手当て
    config_tcpudp.c のTCP通信端点設定(tcp_ccep構造体)とTCP受付口(tcp_crep構造体)を見直しましょう。
    R20AN0314JJ0100のサンプルはRXマイコンの各種ボード用にWebサーバ、FTPサーバ、
    DNSクライアント、DHCPクライアントを実装したものですね。
    https://www.renesas.com/ja-jp/software/D6000403.html
    ⇒RX65Nの発売に合わせて更新されたようです。

    上記サンプルだと以下のようになっています。
    それぞれ1行1IDとなります。

    通信端点IDは各APIの第1引数に、受付口IDはtcp_acp_cep()の第2引数に指定します。
    通信端点IDはシステム上複数動作しているアプリを識別するための番号、
    受付口IDはtcp_acp_cep()で待ち受けるポート番号を識別するための番号ですね。
    ゼロになっているところは未実装の設定フィールドです。
    例外として通信端点の1個目のメンバーでEtherのチャネル番号を指定できるようです。

    たとえば、下記設定のシステムでtcp_acp_cep(5, 5, ...); と指定すると、21番ポートで待ち受けて、
    接続が完了するとftp_callback()が呼び出される、という寸法ですね。

    T_TCP_CREP tcp_crep[] =
    {
        { 0x0000, { 0, 21 }}, /* 受付口ID=1 */
        { 0x0000, { 0, 20 }}, /* 受付口ID=2 */
        { 0x0000, { 0, 21 }}, /* 受付口ID=3 */
        { 0x0000, { 0, 20 }}, /* 受付口ID=4 */
        { 0x0000, { 0, 21 }}, /* 受付口ID=5 */
        { 0x0000, { 0, 20 }}, /* 受付口ID=6 */
     { 0x0000, { 0, 80 }}, /* 受付口ID=7 */
     { 0x0000, { 0, 80 }}, /* 受付口ID=8 */
     { 0x0000, { 0, 80 }}, /* 受付口ID=9 */
     { 0x0000, { 0, 80 }}, /* 受付口ID=10 */
    }

    T_TCP_CCEP tcp_ccep[] =
    {
     { 0, 0, 0, 0, 128, ftp_callback },   /* 通信端点ID=1 */
     { 0, 0, 0, 0, 1460, ftp_data_callback }, /* 通信端点ID=2 */
     { 0, 0, 0, 0, 128, ftp_callback },   /* 通信端点ID=3 */
     { 0, 0, 0, 0, 1460, ftp_data_callback }, /* 通信端点ID=4 */
     { 0, 0, 0, 0, 128, ftp_callback },   /* 通信端点ID=5 */
     { 0, 0, 0, 0, 1460, ftp_data_callback }, /* 通信端点ID=6 */
     { 0, 0, 0, 0, 1460, http_callback },  /* 通信端点ID=7 */
     { 0, 0, 0, 0, 1460, http_callback },  /* 通信端点ID=8 */
     { 0, 0, 0, 0, 1460, http_callback },  /* 通信端点ID=9 */
     { 0, 0, 0, 0, 1460, http_callback },  /* 通信端点ID=10 */
    }

    手当②:FTPサーバとWebサーバのコンフィグの手当て
    次にFTPサーバとWebサーバのコンフィグの手当てをします。
    コンフィグファイルは、r_t4_http_server_rx_config.h、r_t4_ftp_server_rx_config.hです。
    それぞれHTTP_START_TCP_CEP、FTP_START_TCP_CEPというのがあります。
    デフォルトだとどちらも"0"になっています。
    HTTP_START_TCP_CEPを6、FTP_START_TCP_CEPを0とすると良いでしょう。
    (通信端点は1からスタートなのに、FTPサーバとWebサーバの設定は0からスタート、混乱してしまいます)

    > if(ercd != E_WBLK){でwhile (1);にはまりますなにが足りないのかな?

    おそらくですが、FTPサーバとWebサーバとで同じ通信端点に対しtcp_acp_cep()を発行してしまい、
    E_QOVRが戻ってきているものと思われます。上記調整で解消するのではないでしょうか。

    > もしかしたら、リアルタイムOS用のブロッキングコール用のソース?

    これは今のところ関係ないと思います。

    > とりあえず、while (1);をreturn;にしてやりました、

    この対処だとウェブサーバは動作しないと思います。

    以上です

  • シェルティさん

    いつもありがとうございます、

    助かりました、以下のように

    const T_TCP_CCEP tcp_ccep[] =

    {

    //1.属性 ,

    //2.送信ウィンドウの先頭アドレス,

    //3.送信ウィンドウのサイズ,

    //4.受信ウィンドウの先頭アドレス,

    //5.受信ウィンドウのサイズ,

    //6.コールバックルーチンアドレス(関数名)

    //  コールバック機能を使用しない場合には、NULL(=0)を設定

    { 0, 0, 0, 0, 128, ftp_callback },//ID=1 ->FTP_START_TCP_CEP 0

    { 0, 0, 0, 0, 1460, ftp_data_callback },//ID=2

    { 0, 0, 0, 0, 128, ftp_callback },//ID=3

    { 0, 0, 0, 0, 1460, ftp_data_callback },//ID=4

    { 0, 0, 0, 0, 128, ftp_callback },//ID=5

    { 0, 0, 0, 0, 1460, ftp_data_callback },//ID=6

    { 0, 0, 0, 0, 1460, http_callback },//ID=7 ->HTTP_START_TCP_CEP 6

    { 0, 0, 0, 0, 1460, http_callback },//ID=8

    { 0, 0, 0, 0, 1460, http_callback },//ID=9

    { 0, 0, 0, 0, 1460, http_callback },//ID=10

    { 0, 0, 0, 0, 128, t4_callback },//ID=11 ->TELNET_START_TCP_CEP 10

    { 0, 0, 0, 0, 128, t4_callback },//ID=12

    { 0, 0, 0, 0, 128, t4_callback },//ID=13

    };

    このようにしましたら、FTP、HTTP、TELNETで支障なくcallback を呼び出すことができました

    引き続きやってみます。

  • お世話になります

    t4_callback内のTFN_TCP_ACP_CEP:は確立済みと思いまして、tcp_snd_dat(cepid,をやってtelnetターミナル画面には文字が表示されます、その後case TFN_TCP_SND_DAT:からlen=(int)tcp_rcv_dat(を実行しますと、E_QOVR 、E_WBLK、E_WBLK等で受信に失敗します、アドバイスいただけませんか?

  • tcp_snd_dat(cepid,をやってtelnetターミナル画面には文字が表示されます、そこをbreak;しますとE_QOVR は出ません、後E_WBLKノンブロッキングコール受付ですがこれは何を意味するのか?

  • E_WBLK len=-83 E_WBLK len=-83 これは正常なt4_callbackでもこれを返すようです、正常であればデータ数を返すとなっていますがtelnetの画面はエコーしているのですが、tcp_rcv_datの返り値はE_WBLKです、送信の数値を見るとercdはrercd=1です、ということは返り値で判断せずrercdでデータ数を判断できるということのように理解したほうが良さそうです。

  • t4_callbackですが受信から始めないといけないみたいで、最初に、tcp_snd_dat(をやってしまいますとその後telnet応答しなくなります

    tcp_rcv_datを先にしますと(telnetタミナル送信から)しますとその後やり取りができるようです、telnetの場合先にtcp_snd_datをやりたいのでこれをどうするか思案中です。

  • IKUZOさん

    シェルティです、こんにちは。

    下記回答します。

    > t4_callback内のTFN_TCP_ACP_CEP:は確立済みと思いまして、
    > tcp_snd_dat(cepid,をやってtelnetターミナル画面には文字が表示されます、
    > その後case TFN_TCP_SND_DAT:からlen=(int)tcp_rcv_dat(を実行しますと、
    > E_QOVR 、E_WBLK、E_WBLK等で受信に失敗します、アドバイスいただけませんか?

    →続きのレスで解決しておられますね。
     ご推察の通り、tcp_snd_dat()の後にbreak;が必要です。
     1回のコールバックで発行できるAPIは通信端点毎に1個だけです。
     なぜならば、このTCP/IPは同一通信端点に対しリクエストを
     キューイングできないからです。

    > tcp_snd_dat(cepid,をやってtelnetターミナル画面には文字が表示されます、
    > そこをbreak;しますとE_QOVR は出ません、後E_WBLKノンブロッキングコール受付ですがこれは何を意味するのか?

    →E_WBLKは「ノンブロッキングコールを受け付けた」という意味です。

    > E_WBLK len=-83 E_WBLK len=-83 これは正常なt4_callbackでもこれを返すようです、
    > 正常であればデータ数を返すとなっていますがtelnetの画面はエコーしているのですが、
    > tcp_rcv_datの返り値はE_WBLKです、送信の数値を見るとercdはrercd=1です、
    > ということは返り値で判断せずrercdでデータ数を判断できるということのように理解したほうが良さそうです。

    →ノンブロッキングコールの場合コールバック関数の第3引数のポインタの先に受信APIの実行結果(受信データ長)が入っています。
     APIをノンブロッキングコールした瞬間はデータ受信はしておらず、先に説明した通り、
     「ノンブロッキングコールを受け付けた」という意味のエラーコードE_WBLKが戻ってくるわけですね。
     少し注意が要るのが、TCP/IPはストリーム型通信といってストリームの終わりはアプリが判断しないと
     いけないことです。これはTCP/IPに10バイト送れと命令してもTCP/IPや通信経路上の通信機器がその場の都合で
     データを分割することがあるためです。このため、アプリは希望するデータ長、または、使用するプロトコルで
     規定された終了コードが来るまで受信データをバッファリングし、受信終了条件を満たすかどうかを
     受信コールバック毎に判定する必要があります。
     
    > t4_callbackですが受信から始めないといけないみたいで、最初に、
    > tcp_snd_dat(をやってしまいますとその後telnet応答しなくなります
    > tcp_rcv_datを先にしますと(telnetタミナル送信から)しますとその後やり取りができるようです、
    > telnetの場合先にtcp_snd_datをやりたいのでこれをどうするか思案中です。

    →t4_callback()内に以下switch-caseをbreak;付きで用意しましょう。
     これでmain()や他の通信端点と非同期に延々と通信を行う循環機構が完成します。
     この骨組みを維持すればあとは送信データを加工したり、受信データに応じた処理をしたり、
     自由に作れます。
     
     TFN_TCP_ACP_CEP:
       tcp_snd_dat(...);
       break;
     TFN_TCP_SND_DAT:
       tcp_rcv_dat(...);
       break;
     TFN_TCP_RCV_DAT:
       tcp_cls_cep(...);
       break;
     TFN_TCP_CLS_CEP:
       tcp_acp_cep(...);
       break;

     接続完了コールバック(TFN_TCP_ACP_CEP)→送信(tcp_snd_dat)→
     送信完了コールバック(TFN_TCP_SND_DAT)→受信(tcp_rcv_dat)→
     受信完了コールバック(TFN_TCP_RCV_DAT)→切断(tcp_cls_cep)→
     切断完了コールバック(TFN_TCP_CLS_CEP)→接続待ち(tcp_acp_cep)→
     <繰り返し>

     先に述べた受信のバッファリングは今後手当していってください。
     ウェブサーバのコードがこのあたりのバッファリングをどのようにしているか
     参考にできると思います。
     
    以上です