質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.03%

C#とArduino(Due)を用いたTCP通信による文字列の送受信におけるサイズについて

解決済

回答 2

投稿

  • 評価
  • クリップ 1
  • VIEW 5,049

score 11

PC(C#)とArduino Due + Ethernet Shieldの構成で、TCP通信を用いてArduinoから文字列を受信するプログラムを作成しました。

手順は以下の通りです。
1. Arduino側で要素数4097(内1要素は終端null)のchar型配列sendMsgを定義し、4096要素に適当な文字を格納して送信
2. C#で文字列を受け取り、0~4095まで1文字ずつ表示する

上記を実行すると、以下のような問題が発生しました。
・C#側では0~2047要素しか受信できず、2048要素目を表示しようとして、例外(IndexOutOfRangeException)が発生する


コアとなるソースコードは以下の通りです。ただし、コネクションの確立は既に行われているものとします。

Arduinoによる文字列の送信
/* Arduino Language */
char sendMsg[4097];
EthernetClient client;
・・・
client.print(sendMsg);
    //serverとの接続は行われ、sendMsgには適当な文字が0~4095要素に格納されているものとする


C#による文字列の受信
/*
ns:接続先とデータの通信を行うためのNetworkStreamクラスのインスタンス
resBytes:受信データを格納するためのbyte型配列(要素数4097)
ms:受信データを蓄積するためのMemoryStreamクラスのインスタンス
ad_buf:受信データを文字列として格納するための変数
enc:UTF-8形式のエンコーディング
*/

/* データ受信部の処理 */
do
{
    int resSize = ns.Read(resBytes, 0, resBytes.Length);
    if(resSize == 0)
    {
        break;
    }
    ms.Write(resBytes, 0, resSize);

}while(ns.DataAvailable);

ad_buf = enc.GetString(ms.ToArray());
ms.SetLength(0);

Thread.Sleep(100);

for(int i=0; i<4096; i++)
{
    Console.WriteLine("{0}:{1}", i, ad_buf[i]);
        //2048要素目の出力で例外処理が発生する
}

原因特定を速める目的で、重要となる部分以外をかなり省略させて頂きました。

理想的には0~4095要素の文字を受信し、1文字ずつ表示するようにしたいのですが、上記のプログラムを実行すると2047文字までしか受信できず、それ以降の文字を取得することができないと言った問題が発生しました。

このような問題が発生する原因とその対処法をご教授頂くべく、今回質問させて頂きました。

必要な情報が落ちているという指摘があった場合、追って載せさせて頂きます。

ご回答の程、宜しくお願い致します。


念のため、通信を行う各端末のスペックを記載します。
PC
型:Let'snote CF-S10
OS:Windows7 Professional 64bit
CPU:Corei5 2540M 2.6GHz
メモリ:4GB
詳細の仕様
http://panasonic.biz/pc/doc/catalist/pdf/S10E.pdf


Arduino Due
MCU:AT91SAM3X8E(Cortex-M3)
Clock:84MHz
Flash Memory:512KB
SRAM:96KB
詳細の仕様
http://arduino.cc/en/Main/arduinoBoardDue

Arduino Ethernet Shield
詳細の仕様
http://arduino.cc/en/Main/ArduinoEthernetShield
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • lichten

    2015/04/14 17:37

    wakuwakuさんが指摘している問題が一番重要ですが、問題になるインデックスが想定のピタリ半分というのも気になりますね。
    おそらくASCIIコードしか入っていないUTF-8だから、文字数=バイト数、という見込みでプログラムを書かれているのだと思います。
    しかし仮に、1文字で複数バイト使用する文字が入ると問題になるコードになっています。
    ms.ToArray() の結果を、そのまま1バイト毎に出力すると何かわかるかもしれません。

    キャンセル

  • masaroid

    2015/04/14 23:57

    解決のご提案ありがとうございます。
    lichtenさんの仰る通りで、送信する文字は1文字1バイトの文字のみを想定しているため、上記のような記述と致しました。

    インデックスが想定の半分になるというご指摘を受け、Arduino側で送信するデータサイズを倍の8192byteに変えてみたところ、C#側で受信できたデータサイズは変わらず2048byteという結果になりました。
    ms.ToArray()の結果を1文字ずつ読み込んだ場合は、0~2047の要素で送信した時の文字と完全に一致することを確認しました。
    こうなると、根本的に送信側で2048byteしか送信できていない可能性も考えられます。
    引続き、原因を究明して行きたいと思います。

    キャンセル

  • wakuwaku

    2015/04/15 07:20

    PC側でパケット監視ツール(wiresharkなど)を使って

    届いているが受信できないのか
    そもそも届いていないのか

    を調べてみるといいかもしれませんね。

    キャンセル

回答 2

checkベストアンサー

+1

具体的な解決策は示せないのですが、確認のため client.print() の返り値をチェックして 4096バイト送れているか確認してみてはいかがでしょうか?
あと 2048バイトずつ2回に分けて送信して変化を確認してみるとか。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/04/17 14:47

    連絡が遅くなり恐縮です、解決案のご提示ありがとうございます。
    ご提案を受け、Arduinoから送信されるパケットのサイズを確認したところ、確かに2048バイトしか送られていないことを確認しました。
    ネックとなっていた原因を割り出すことができたので、その見解を以下に記します。

    ・TCP通信を担うEthernet Shieldに搭載されているマイコン「W5100」が、1つのソケットにつき1度に送受信可能なサイズが2KBである

    上記の仕様がネックとなり、2048バイト以上のデータが送られないという結論に至りました。

    Ethernet Shieldの簡単な仕様は以下の通りです。
    ・送受信に割り当てられてるメモリ:8KB
    ・同時に接続できるソケット数:4つ

    総メモリ数は8KBですが、4つのソケットにそれぞれ分割して割り当てられているため、1ソケットにつき2KBとなっているようです。

    W5100のデータシートを参考にしました。
    URL:https://www.sparkfun.com/datasheets/DevTools/Arduino/W5100_Datasheet_v1_1_6.pdf


    解決法としては、lazy_tsanさんのご提示頂いた「2048バイトずつ分割して送信する」方法を実装して、受信側で2048バイト以上のデータが受信できるように実装致しました。


    原因究明に最も近付いたこと・原因に対する解決策まで導いて頂いたことを加味して、lazy_tsanさんをベストアンサーにさせて頂きます。
    回答及び情報の提示をしてくださった皆様に、お礼を申し上げます。

    キャンセル

0

NetworkStream.DataAvailableプロパティはデータをすべて受信したことを示しません。
あくまでストリームに読み込み可能なデータがあるかを示します。

以下を参考にどうぞ。
NetworkStream でデータを最後まで Read する方法について

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/04/14 23:43

    解決のご提案ありがとうございます。
    DataAvailableプロパティは全てのデータを受信したという判定には向かないのですね。

    Arduinoから送信されるデータのサイズは予め分かっているため、そのデータサイズ分だけ受信するまで待機するという仕様に変更し、実行を行いました。
    しかし、どれだけ待機してもC#側のバッファに溜まるデータサイズは2048byteであることには変わりなく、「全て読み込まれずに処理が終わる」ということが原因では無いようです。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.03%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る