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

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

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

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

TCP

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

デバッグ

デバッグはプログラムのバグや欠陥を検知し、開発中のバグを取り除く為のプロセスを指します。

Q&A

解決済

3回答

2741閲覧

C# TCP/IP送受信が正しくできてるかのデバッグ方法を教えて下さい。

changryu

総合スコア3

C#

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

TCP

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

デバッグ

デバッグはプログラムのバグや欠陥を検知し、開発中のバグを取り除く為のプロセスを指します。

1グッド

0クリップ

投稿2022/09/07 07:49

前提

先週金曜日に突如業務でプログラムを作ることになった初心者です。
学生時代にプログラミングに挫折した経験から、ど初心者の自分がすぐに作れるほど甘くないことは理解しているつもりですが、それでも社内メンバーで一番PCに詳しいというだけで白羽の矢が立った次第です。
使用する言語は何でも良いとの事だったので、これを機会に将来的に社内ツールなども作れるようになったら良いなと思いC#を使うことにしました。
週末に参考書を買い、Microsoft Visual Studio Community 2022をインストールしいざプログラム作成を開始しました。
この三日間ググりながら少しづつトライ&エラーをしてきましたが、「15分調べてもわからないことは、teratailで質問しよう ...」というのが目に入り、こちらで質問させて頂くことにしました。
諸先輩方、分からないことが分からず質問も変な初心者ですが、どうぞ宜しくお願い致します。

実現したいこと

キーエンスのレーザーマーカーをWindowsPCからTCP/IP通信を使って制御したいです。

そこでまずはTCP/IP通信を行えるフリーソフトを使って制御できるかをテストしました。
使用したフリーソフトはNonSoft様(http://nonsoft.la.coocan.jp/ )が公開しているTCP/IPテストツールを使わせて頂きました。

イメージ説明

キーエンスのマニュアルを片手にTCP/IPにて問題なく制御できることが確認できました。
こちらのツールをこのまま使わせて頂くことも方法の一つだとは思うのですが(業務で使う為NonSoft様への交渉は必要かと思いますが)、最終的には自分でレーザーマーカー制御に特化したソフトを作りたいと考えています。

発生している問題・エラーメッセージ

先にお見せしたTCP/IPツールのようにコマンドを送信(送->)をすると、即座にレスポンス(->受信)が返ってくることが分かっています。
私の作ったプログラムで同じコマンドを送信しても、受信が返ってこずタイムアウトしている”よう”です。

イメージ説明

タイムアウトしている”よう”と書かせて頂いたのも、接続はできているようなのですが、正しくコマンドが送信できているか?または正しく受信ができているのかが分からない為です。

もし正しくコマンドが送信できているということや、そもそもプログラムが間違っており受信にすら至っていないなどデバッグ方法があればご教授頂けないかと思い、こちらに記載させて頂きました。

該当のソースコード

基本的に、育児パパの人生備忘録様(https://t19488sns.com/socket/370/ )と dobon.net様(https://dobon.net/ )を参考にさせて頂いています。

Formに受信した内容をListBoxに表示しようと考えていますが、まだ実装できていません。

イメージ説明

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Net.Sockets; using System.Net.NetworkInformation; using System.IO; namespace TCP_Client { public partial class Form1 : Form { public Form1() { InitializeComponent(); } TcpClient tcp; //定義 private void btnSend_Click(object sender, EventArgs e) { try { string tmp; int hoge; Get_TCPServer(out tmp, out hoge); //オープン //OpenTcpClient(tmp, hoge); tcp = new TcpClient(tmp, hoge); //送受信 //NetworkStreamを取得する NetworkStream ns = tcp.GetStream(); //読み取り、書き込みのタイムアウトを10秒にする //デフォルトはInfiniteでタイムアウトしない //(.NET Framework 2.0以上が必要) ns.ReadTimeout = 1000; ns.WriteTimeout = 1000; //サーバーにデータを送信する //文字列はByte型配列に変換 Encoding enc = Encoding.UTF8; //byte[] sendBytes = enc.GetBytes(tmp + '\n'); byte[] sendBytes = enc.GetBytes(tmp); //データを送信する ns.Write(sendBytes, 0, sendBytes.Length); //サーバーから送られたデータを受信する MemoryStream ms = new MemoryStream(); byte[] resBytes = new byte[256]; int resSize = 0; do { //データの一部を受信する resSize = ns.Read(resBytes, 0, resBytes.Length); //Readが0を返した時はサーバーが切断したと判断 if (resSize == 0) { Console.WriteLine("サーバーが切断しました。"); break; } //受信したデータを蓄積する ms.Write(resBytes, 0, resSize); //まだ読み取れるデータがあるか、データの最後が\nでない時は、 //受信を続ける } while (ns.DataAvailable || resBytes[resSize - 1] != '\n'); //受信したデータを文字列に変換 string resMsg = enc.GetString(ms.GetBuffer(), 0, (int)ms.Length); ms.Close(); //末尾の\nを削除 resMsg = resMsg.TrimEnd('\n'); //閉じる ns.Close(); tcp.Close(); } catch(Exception ex) { MessageBox.Show(ex.Message, "エラー発生"); } } private void Get_TCPServer(out string ipadd, out int port) { port = (int)nudport.Value; //ポートは簡単 ipadd = ""; //IPの取得(IPパラメータ4つ分取得) for (int n = 0; n < 4; n++) { //コントロール名から設定を取得 NumericUpDown nud = (NumericUpDown)this.Controls["nudIP" + (n + 1).ToString()]; if (nud == null) { MessageBox.Show("こんとろーる取得失敗"); return; } //最初だけカンマ無し ipadd += (n == 0) ? nud.Value.ToString() : "." + nud.Value.ToString(); } } private bool Send_Ping(string ip) { //Pingのインスタンス生成 Ping sender = new Ping(); //ping送信 PingReply reply = sender.Send(ip, 10000); return (reply.Status == IPStatus.Success) ? true : false; } private void btnCheck_Click(object sender, EventArgs e) { //検索するIPアドレスを取得する string tmp; int hoge; Get_TCPServer(out tmp, out hoge); //pingの送信 bool res = Send_Ping(tmp); //結果に応じて、表示の変更 string mes = (res == true) ? "存在確認OK" : "接続不可"; MessageBox.Show(mes); } } }

試したこと

送受信時のタイムアウトの時間を延ばすことや、受信メッセージの改行コード\nを取ってみたり。
これ以上何をすれば良いか分からずいます・・・m(_ _)m

補足情報(FW/ツールのバージョンなど)

Microsoft Visual Studio Community 2022
Version 17.2.4
VisualStudio.17.Release/17.2.4+32602.215
Microsoft .NET Framework
Version 4.8.04084

インストールされているバージョン:Community

ASP.NET and Web Tools 2019 17.2.392.13739
ASP.NET and Web Tools 2019

Azure App Service Tools v3.0.0 17.2.392.13739
Azure App Service Tools v3.0.0

C# ツール 4.2.0-4.22281.5+8d3180e5f00d42f0f0295165f756f368f0cbfa44
IDE で使用する C# コンポーネント。プロジェクトの種類や設定に応じて、異なるバージョンのコンパイラを使用できます。

Common Azure Tools 1.10
Provides common services for use by Azure Mobile Services and Microsoft Azure Tools.

Microsoft JVM Debugger 1.0
Provides support for connecting the Visual Studio debugger to JDWP compatible Java Virtual Machines

NuGet パッケージ マネージャー 6.2.1
Visual Studio 内の NuGet パッケージ マネージャー。NuGet の詳細については、https://docs.nuget.org/ にアクセスしてください

TypeScript Tools 17.0.10418.2001
TypeScript Tools for Microsoft Visual Studio

Visual Basic ツール 4.2.0-4.22281.5+8d3180e5f00d42f0f0295165f756f368f0cbfa44
IDE で使用する Visual Basic コンポーネント。プロジェクトの種類や設定に応じて、異なるバージョンのコンパイラを使用できます。

Visual F# Tools 17.1.0-beta.22274.4+211fd760c2315d73cfa0d375fe64abb346bc1096
Microsoft Visual F# Tools

Visual Studio IntelliCode 2.2
Visual Studio 向けの AI 支援付き開発。

TN8001👍を押しています

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

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

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

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

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

dodox86

2022/09/07 12:32

基本的には既にいただいている複数の回答のようにクライアントアプリ側でまず送受信データが正しいかどうか確認してから実機に接続して確認をすべきですが、キーエンスのレーザーマーカー自体に送受信データのログ保存機能があったりするので、レーザーマーカーとそのサポートソフトの機能をマニュアルで確認すると良いです。質問者さんがお使いの機種でそういったものがあるかは分かりかねますが、実機での問題の確認に役に立ちます。
guest

回答3

0

ベストアンサー

TCP/IP は、下位層でリカバリ処理などをやっているので、エラーが発生しないかぎり、こちらが送ったものは向こうに届くし、相手が送ったものはこちらに届きます。

ですので、デバッガで Send メソッドに渡したデータや Recv メソッドで受信したデータを確認すれば充分デバッグは可能と思います。

キーエンスのレーザーマーカーは、デリミタは "\r" で、コマンド+"\r" を送ると、レスポンスとして レスポンス+"\r" が返ってくる仕様のようですね。

「育児パパの人生備忘録」に掲載されているコードはデリミタが "\n" になっているので修正する必要があります。

StreamWriter/StreamReader クラスを使用すると、かなり楽になります。

接続してコマンドを送信し、レスポンスを受信し、切断するといった処理をひとまとめにすると、こんな感じになります。(エラー処理は省いてます)

C#

1static string SendAndRecv(string ipAddr, int port, string command) { 2 using (var tcp = new TcpClient(ipAddr, port)) { 3 NetworkStream ns = tcp.GetStream(); 4 ns.ReadTimeout = 1000; 5 ns.WriteTimeout = 1000; 6 using (StreamWriter writer = new StreamWriter(ns, Encoding.UTF8)) 7 using (StreamReader reader = new StreamReader(ns, Encoding.UTF8)) { 8 writer.NewLine = "\r"; 9 writer.WriteLine(command); 10 writer.Flush(); 11 return reader.ReadLine(); 12 } 13 } 14}

btnSend_Click は以下のようになります。

C#

1private void btnSend_Click(object sender, EventArgs e) { 2 string ipadd; 3 int port; 4 Get_TCPServer(out ipadd, out port); 5 listBox1.Items.Add(SendAndRecv(ipadd, port, txtCommand.Text)); 6}

おまけ

TextBox を継承し、CreateParams で、ClassName に "SysIPAddress32" を指定すると、IPアドレス入力用の TextBox が出来ます。

C#

1using System.Windows.Forms; 2 3class AddressTextBox : TextBox 4{ 5 protected override CreateParams CreateParams { 6 get { 7 var cp = base.CreateParams; 8 cp.ClassName = "SysIPAddress32"; 9 return cp; 10 } 11 } 12}

ビルドしてコンパイルが通れば、フォームデザイナのツールボックスの上のほうに、カスタムコントロールが追加されます。

AddressTextBox

図のように入力すると、Text プロパティには "192.168.0.1" と入っています。

投稿2022/09/07 11:23

KOZ6.0

総合スコア2626

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

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

changryu

2022/09/08 05:28

KOZ6.0様 この度は早速のご回答ありがとうございました。 まず、キーエンスのレーザーマーカーに使うデリミタの件について情報ありがとうございました。 その通りでした。デリミタは\nだと思い込んでいました。 おかげさまで送信時、受信時に一個一個確認してみてどう変化するのかが分かりより理解が深まりました。 最終的にちゃんとレーザーマーカーを制御でき、またレスポンスも受け取ることができました。 それとStreamWriter/StreamReader クラスの情報と、IPアドレス入力用のTextBoxの作り方についてご教授頂き感謝いたします。 今回、すぐにでも使おうかと思ったのですが、もう少し自分の知識が深まり、必要性を感じる。または理解して使う方が有益だと思いましたので、もう少し勉強してから活用させて頂きたいと思います。 当初お聞きした質問以外にも、発展形の情報まで頂き誠に感謝致します。改めてありがとうございました。
KOZ6.0

2022/09/08 08:48 編集

StreamReader を使わないのであれば、受信の終了条件で、ns.DataAvailable を参照するのはやめてください。 というのはレスポンスの長さが長くなり、パケットが MTU 値を超えると分断されて送信されます。 つまり、デリミタを受信していないが、データが届いていないという状況が発生する可能性があります。
changryu

2022/10/20 05:27

KOZ6.0様 コメント頂いて居たのにも関わらず、返答が遅くなり申し訳ございませんでした。 前回より一ヶ月以上立ってしまいましたが、別件の仕事をしながら少しずつC#の勉強をしてきて、メソッドやクラスの使いからが少しづつ理解し始めたのと同時に、前回質問したプログラムの可読性が悪い気がしてきて やっとKOZ6.0様がアドバイスしていただいた、ソースの良さが分かってきました(なんとなくですが...)。 またおまけで教えて頂いたIPアドレスのテキストボックスもカスタムコントロールの作り方がやっと分かり、利用させて頂いています。 どちらもシンプルでスマートで良いプログラムですね。 ただいまTCP/IP送受信プログラムをKOZ6.0様のソースを反映させテストしていますが、コマンド送信部分だと思うのですが、ちょっと苦戦しています。また質問してしまうかも知れませんがその際は改めてアドバイスを頂けるとありがたい限りです。 以上宜しくお願い致します。
KOZ6.0

2022/10/20 05:50

StreamWriter を使っていてひっかかりそうなところは、WriteLine しただけでは送信されないことですかね。 Flush しないと相手側に送られません。
changryu

2022/10/20 06:52

毎度、ご迷惑をおかけして申し訳ございません。 現在、以下のプログラムの流れを負いながら確認しています。 using (StreamWriter writer = new StreamWriter(ns, Encoding.UTF8)) using (StreamReader reader = new StreamReader(ns, Encoding.UTF8)) { writer.NewLine = "\r"; ● writer.WriteLine(command); writer.Flush(); return reader.ReadLine(); } writer.WriteLine(command);の箇所にブレークポイントを起き、その際の値を見ても ウォッチリストにてcommandに "WX, Lighting=1\r" となっていたので、1行前のNewLine = "\r"も効いていると考えており、 前回のハマりポイントはクリアされているのではないかなーと思いながら、小さな小細工(コマンドテキスト直下書きなど)をしながら 何が影響しているのか微力ですが確認しています。 ご指摘のFlushも流れ的にされていると考えているのですが・・・ もしその他お気づきの点があればご教授頂ければ有り難い限りです。 お忙しい中、ご面倒をおかけ致しますが、どうぞ宜しくお願い致します。
KOZ6.0

2022/10/20 07:41 編集

command の中身に \r を含めてはいけません。 WriteLine は NewLine を付加して送ります。 相手側には "WX, Lighting=1\r\r" が送られているはずです。
KOZ6.0

2022/10/20 11:17 編集

command の中身に \r を含める場合は、Write メソッドを使用してください。
changryu

2022/10/21 07:55

KOZ6.0様 この度はお世話になります。 夜分コメントありがとうございました。 まずcommandに直接"\r"は入れてはおらず、writer.NewLine = "\r";が実行されcommand変数の"WX, Lighting=1\r"の状態になっているものと考えていました。 ただご指摘いただいた通り、 もしかしたら"WX, Lighting=1"にそもそも\rが入っており、"WX, Lighting=1\r\r"になっているのでは?と疑い、 command = "WX,Lighting=1"; //(改行コードが問題か検証してみる)改行コードを削除 command = command.Replace("\r", "").Replace("\n", ""); writer.NewLine = "\r"; writer.WriteLine(command); writer.Flush(); return reader.ReadLine(); としテストしてみましたが症状は変わりませんでした。 私の力不足によりご迷惑をおかけしましたが、ひとまず以前のプログラムでレーザーマーカーは制御できますので、こちらのプログラムについてはもう少しじっくりと考えてみたいと思います。 可読性、将来的に別の人がこのプログラムを引き継いたときの事を考えると、KOZ6.0様に教えて頂いたプログラムを使いたいので、もし解決しましましたら、こちらにてご報告をさせて頂きたいと思います。 ひとまず、お礼を申し上げます。ありがとうございましたm(_ _)m
KOZ6.0

2022/10/21 08:42 編集

あ、reader に改行コードを指定していないですね。
guest

0

byte[] sendBytes = enc.GetBytes(tmp);
ここのtmpはip addressを指したままのように見えますね

投稿2022/09/07 07:59

matukeso

総合スコア1590

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

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

changryu

2022/09/08 05:14

matukeso様 この度は早速のご回答ありがとうございました。 参考にしたソースを深く考えずに使っており、ご指摘を受けちゃんと見直してみたらその通りでした。 一行一行、何をしているのか、自分が何をしたいのかちゃんと考えるクセをつける良いきっかけになりました。 改めてお礼申し上げます。
guest

0

デバッグ方法

機器に送るのではなく、「TCP/IPツール」、つまり自分(PC)に送り、「TCP/IPツール」の表示をみて
送信コマンドが意図通りかを見ます。


末尾に<CR>とつけて送っているようですが、
多分末尾につけるべきは制御文字のキャリッジリターンであって
<, C, R, > という4文字では無いと思います。
コードを見ても特に変換している様子がないのでおそらくそこを勘違いしていると思います。


それ以前にコマンド用のテキストボックスの文字列を参照しているように見えませんね。

投稿2022/09/07 07:58

編集2022/09/07 08:01
ozwk

総合スコア13521

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

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

changryu

2022/09/08 05:10

ozwk様 早速のご回答ありがとうございました。 デバッグ方法・・・自分に送り意図通りかを見る。について勉強になりました。焦りからか視野が狭くなっていたことに気づかされました。 <CR>の件・・・深く考えず使うモノだと何も考えずに付加していました。ちゃんと何のために必要かを改めて調べてみました。 テキストボックスの文字列・・・改めて自分のソースコードを見直しましたが、本当にその通りでした(汗)そもそも参考書には最初の方にブレイクポイントの使い方が書かれていたのに今更この件を検証する際に使いました。 お気づきの点を列挙して頂き、誠にありがとうございました。 周りに相談できる相手がいなかったので、この度はすごく勉強になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問