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

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

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

TCP

TCP(Transmission Control Protocol)とは、トランスポート層のプロトコルで、コネクション型のデータサービスです。

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

Q&A

解決済

2回答

7738閲覧

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

masaroid

総合スコア10

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

TCP

TCP(Transmission Control Protocol)とは、トランスポート層のプロトコルで、コネクション型のデータサービスです。

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

0グッド

1クリップ

投稿2015/04/13 04:03

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による文字列の送信

lang

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

C#による文字列の受信

lang

1/* 2ns:接続先とデータの通信を行うためのNetworkStreamクラスのインスタンス 3resBytes:受信データを格納するためのbyte型配列(要素数4097) 4ms:受信データを蓄積するためのMemoryStreamクラスのインスタンス 5ad_buf:受信データを文字列として格納するための変数 6enc:UTF-8形式のエンコーディング 7*/ 8 9/* データ受信部の処理 */ 10do 11{ 12 int resSize = ns.Read(resBytes, 0, resBytes.Length); 13 if(resSize == 0) 14 { 15 break; 16 } 17 ms.Write(resBytes, 0, resSize); 18 19}while(ns.DataAvailable); 20 21ad_buf = enc.GetString(ms.ToArray()); 22ms.SetLength(0); 23 24Thread.Sleep(100); 25 26for(int i=0; i<4096; i++) 27{ 28 Console.WriteLine("{0}:{1}", i, ad_buf[i]); 29 //2048要素目の出力で例外処理が発生する 30}

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

理想的には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

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

lichten

2015/04/14 08:37

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

2015/04/14 14:57

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

2015/04/14 22:20

PC側でパケット監視ツール(wiresharkなど)を使って 届いているが受信できないのか そもそも届いていないのか を調べてみるといいかもしれませんね。
guest

回答2

0

ベストアンサー

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

投稿2015/04/16 07:42

lazy_tsan

総合スコア51

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

masaroid

2015/04/17 05: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さんをベストアンサーにさせて頂きます。 回答及び情報の提示をしてくださった皆様に、お礼を申し上げます。
guest

0

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

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

投稿2015/04/13 09:19

wakuwaku

総合スコア386

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

masaroid

2015/04/14 14:43

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問