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

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

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

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

Arduino

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

Q&A

2回答

8325閲覧

TCPサーバー(ESP32)がクライアント(C#)の要求に対して応答しなくなる

kawauso

総合スコア56

C#

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

Arduino

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

0グッド

1クリップ

投稿2019/06/11 04:36

お世話になります。

行いたいこと
サーバー: ESP32
クライアント: C#プログラム
上記のような構成でTCP通信したいと考えています。
それぞれは同一のルーターに接続さてています。

問題点
クライアントであるC#プログラムのTcpClientのインスタンスを生成するところで下記のようなエラーが出力されることがあります。
エラーが出力されない場合は、問題なく通信できています。
出力されるタイミングはまちまちです。電源投入後10分ほどでエラーが出力されることもあれば、1時間以上大丈夫なこともあります。
▼エラー文
System.Net.Sockets.SocketException: '接続済みの呼び出し先が一定の時間を過ぎても正しく応答しなかったため、接続できませんでした。
または接続済みのホストが応答しなかったため、確立された接続は失敗しました。'

質問
プログラムを記載します。原因・解決策などご存知の方は教示いただければ幸です。
ESP32の電源に関しては、PCのUSB、乾電池(直列3V)、直流安定化電源(3.3V)を試しました。

プログラム

Arduino

1// サーバー 2#include <WiFi.h> 3 4const char* ssid = "*****"; 5const char* password = "*****"; 6IPAddress ip(192, 168, 11, 100); 7IPAddress gateway(192, 168, 2, 1); 8IPAddress subnet(255, 255, 255, 0); 9 10WiFiServer server(80); 11 12void setup(void) { 13 Serial.begin(9600); 14 15 WiFi.mode(WIFI_STA); 16 WiFi.config(ip, gateway, subnet); 17 WiFi.begin(ssid, password); 18 Serial.println(""); 19 20 // Wait for connection 21 while (WiFi.status() != WL_CONNECTED) { 22 delay(500); 23 Serial.print("."); 24 } 25 Serial.println(""); 26 Serial.print("Connected to "); 27 Serial.println(ssid); 28 Serial.print("IP address: "); 29 Serial.println(WiFi.localIP()); 30 31 server.begin(); 32 Serial.println("HTTP server started"); 33} 34 35void loop(void) { 36 String cmd; 37 cmd = rcvCommand(); 38 39 if (cmd != "") { 40 Serial.print("cmd: "); 41 Serial.println(cmd); 42 } 43 44 delay(100); 45} 46 47String rcvCommand() { 48 WiFiClient client = server.available(); 49 50 String rstr; 51 if (client.connected()) { 52 Serial.println("Connected to client"); 53 54 //コマンド文字列受信(文字列が来なければタイムアウトする) 55 rstr = client.readStringUntil('\r'); 56 Serial.print("["); 57 Serial.print(rstr); 58 Serial.println("]"); 59 60 //応答送信 61 client.print("OK\r"); 62 63 //接続をクローズ 64 client.stop(); 65 Serial.println("Closed"); 66 } 67 68 return rstr; 69}

C#

1// クライアント 2 string sendMsg = "hoge"; 3 string ipOrHost = "192.168.11.100"; 4 //string ipOrHost = "localhost"; 5 int port = 80; 6 7 //TcpClientを作成し、サーバーと接続する 8 // 【ここでエラーが出力されることがあります】 9 System.Net.Sockets.TcpClient tcp = 10 new System.Net.Sockets.TcpClient(ipOrHost, port); 11 Console.WriteLine("サーバー({0}:{1})と接続しました({2}:{3})。", 12 ((System.Net.IPEndPoint)tcp.Client.RemoteEndPoint).Address, 13 ((System.Net.IPEndPoint)tcp.Client.RemoteEndPoint).Port, 14 ((System.Net.IPEndPoint)tcp.Client.LocalEndPoint).Address, 15 ((System.Net.IPEndPoint)tcp.Client.LocalEndPoint).Port); 16 17 //NetworkStreamを取得する 18 System.Net.Sockets.NetworkStream ns = tcp.GetStream(); 19 20 //読み取り、書き込みのタイムアウトを10秒にする 21 //デフォルトはInfiniteで、タイムアウトしない 22 //(.NET Framework 2.0以上が必要) 23 ns.ReadTimeout = 10000; 24 ns.WriteTimeout = 10000; 25 26 //サーバーにデータを送信する 27 //文字列をByte型配列に変換 28 System.Text.Encoding enc = System.Text.Encoding.UTF8; 29 byte[] sendBytes = enc.GetBytes(sendMsg); 30 //データを送信する 31 ns.Write(sendBytes, 0, sendBytes.Length); 32 Console.WriteLine(sendMsg); 33 34 System.IO.MemoryStream ms = new System.IO.MemoryStream(); 35 byte[] resBytes = new byte[256]; 36 int resSize = 0; 37 do 38 { 39 //データの一部を受信する 40 resSize = ns.Read(resBytes, 0, resBytes.Length); 41 //Readが0を返した時はサーバーが切断したと判断 42 if (resSize == 0) 43 { 44 Console.WriteLine("サーバーが切断しました。"); 45 break; 46 } 47 //受信したデータを蓄積する 48 ms.Write(resBytes, 0, resSize); 49 //まだ読み取れるデータがあるか、データの最後が\nでない時は、 50 // 受信を続ける 51 } while (ns.DataAvailable || resBytes[resSize - 1] != '\n'); 52 //受信したデータを文字列に変換 53 string resMsg = enc.GetString(ms.GetBuffer(), 0, (int)ms.Length); 54 ms.Close(); 55 //末尾の\nを削除 56 resMsg = resMsg.TrimEnd('\n'); 57 Console.WriteLine(resMsg); 58 }

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

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

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

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

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

guest

回答2

0

ESP側の
rstr = client.readStringUntil('\r');
に対して、C#側では'\r'を送信しているところが無いような気がします。単に略されてしまっているだけだとは思いますが。もし本当に送っていないならreadStringUntil()がメモリを食い尽くしている、なんていうこともありそうですが、その辺どうなんでしょう。
逆に、ESP側では'\r'を送っているのにC#側では'\n'を終端とみていたり、ちょっと疑問に思えます。

それと、TCPにおいては、データの単位は1バイト以上でも以下でもないので、本来は「データの塊」というものはなく、「データの最後が\nでない時は受信を続ける」という考え方は上手く動くように見えるかも知れませんがしかし危険な気がします。'\n'を受信したらそこまでのデータを一塊と認識する、ならアリだと思いますけれど、'\n'が最後になる保証はなにもないので。

投稿2019/06/11 13:40

thkana

総合スコア7639

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

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

kawauso

2019/06/12 07:12

回答ありがとうございます。 ご指摘いただいたサーバーとクライアント側で終端をそれぞれ「\n」と「\r」で 揃えて試してみましたが、同様のエラーが出力されました。 ただloop内でrcvCommand()を呼ばなければ、安定して動いていることは確認できました。
guest

0

ESP32側でシリアルに動作ログをずっと流しておいてPCでモニタして、そのエラーが出るときになにが起こってるのか見てみることですね。

まあ、考えつくこととしては、ESP32の消費電流が大きくて、電源の電圧ドロップしてリセットかかってしまうってのだけど。

投稿2019/06/11 04:51

y_waiwai

総合スコア87774

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

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

kawauso

2019/06/11 05:22

回答ありがとうございます。 直流安定化電源(A&D AD-8724D)を使用していますが、電圧降下するものなのでしょうか。 電圧降下しないようにする対策などはあるのでしょうか。
y_waiwai

2019/06/11 05:28

接続状況にもよります 3.3Vを直接供給してる場合、0.2Vほどのスパイクでもリセットが働きます が、まずはログを確認して、エラーが起きるときにリセットがかかってるのかを調べてみては
kawauso

2019/06/11 05:38

回答ありがとうございます。 リセットが掛かったかどうかのログはどのように記述すればよいでしょうか。 エラーの際にsetupのprint文が実行される=リセットがかかったとういことでしょうか。
y_waiwai

2019/06/11 05:48

ああ、エラーのときにsetupが実行されてるならリセットがかかってますね なら電源周りを強化しないといけないですね いくら頑強な電源を用意してても、長い線でつないでたら電流の変化で電圧ドロップします ESP32の直近に3.3Vの3端子レギュレータをつけて、5V程度以上の電源で駆動すればいいです
kawauso

2019/06/11 06:40 編集

すみません。書き方が悪かったようです。 上記のものは「このようになれば、リセットが掛かったことになりますか?」という意味で書きました。 実際にエラー時にリセットがかかって再度setupが実行するかを確認しましたが、setupのprint文は実行されませんでした。 この状態でESP32に対してpingを打ってみましたが要求はタイムアウトされました。
ozwk

2019/06/12 07:32

Core Debug levelを"Verbose"にしてスケッチを書き込むとESP32が詳細なログを吐くようになります これで確認してみてはどうでしょう。
kawauso

2019/06/12 07:49

回答ありがとうございます。 Core Debug levelを"Verbose"にしてスケッチを書き込んでシリアルモニタで監視しましたが、エラー時に何の出力もありませんでした。 スケッチ自体に変更を加える必要はあるのでしょうか。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問