UDP/IPでバイナリデータ送信

タグの編集
投稿者 ポムNNN  (社会人) 投稿日時 2017/9/21 20:13:45
開発環境 Visual Studio 2015, Windows7(64bit)

UDP/IPでバイナリデータを送信して、相手からのレスポンスをバイナリで受信しようとプログラムを作っています。

TCP/IPで同じようなモノを作ったのでTcpClientの部分をUdpClientに変えれば動くと思い色々試したのですが上手くいきません。

下記の場所で GetStreamはUdpClientのメンバーではありません。となります。
Dim stream As NetworkStream = Client.GetStream 

今回のような内容ですと、UdpClientクラス、BinaryWriterクラス、BinaryReaderクラスの組合せで使えないのでしょうか?

自分が作ったプログラムを記載いたしますので、どこを修正すればよいか、ご教授頂けたら嬉しいです。

※例外処理は省いてあります。TcpClientだった所をUdpClientにしてあるだけです。

 Private Sub Binary()

          Dim Client As New UdpClient
            Dim Target_IP As IPAddress = IPAddress.Parse("192.168.1.42")
            Dim Target_Port As Integer = 8000

            Client.Connect(Target_IP, Target_Port)
            Dim stream As NetworkStream = Client.GetStream

        Dim writer As New BinaryWriter(stream)
        Dim reader As New BinaryReader(stream)

        Dim cmd As Byte() = {&H51, &H1, &H0, &H3, &H30, &H31, &H32}

          writer.Write(cmd)
            Console.WriteLine(reader.ReadBytes(7))

            stream.Close()
            writer.Close()
            reader.Close()

    End Sub
投稿者 kiku  (社会人) 投稿日時 2017/9/22 09:25:25
私自身は試していませんが、下記の記事が参考になると思います。
サンプルでは、受信したバイナリデータを文字列に変換していますが
その文字列の変換をしなければ良いと思います。

https://dobon.net/vb/dotnet/internet/udpclient.html
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2017/9/22 10:06:43
> 下記の場所で GetStreamはUdpClientのメンバーではありません。となります。

GetSream を解さずに、UdpClient.Send/UdpClient.Receive メソッドを使うか、
UdpClient.Client プロパティから基の Socket を取り出してみては如何でしょう。

そもそも、TcpClient.GetStream が返す NetworkStream も、元を正せば
 Dim stm As New NetworkStream(myTcpClient.Client, True)
ですし。
https://referencesource.microsoft.com/#System/net/System/Net/Sockets/TCPClient.cs,bf6366b416aed83b
投稿者 ポムNNN  (社会人) 投稿日時 2017/9/23 18:20:40
kiku様、魔界の仮面弁士様、アドバイスありがとうございました。
お二人のアドバイスを元に色々試してみました。結果的にはコマンドを送信し、レスポンスを受信できました。お礼申し上げます。

途中ですが、今回成功したプログラムを記載させていただきます。

     Try
            Dim UdpMyClient As New UdpClient
            Dim Target_IP As IPAddress = IPAddress.Parse("133.113.0.42")
            Dim Target_Port As Integer = 8000

            UdpMyClient.Connect(Target_IP, Target_Port)
            UdpMyClient.Client.ReceiveTimeout = 1000
            UdpMyClient.Client.SendTimeout = 1000

            Dim cmd As Byte() = {&H80, &H0, &H2, &H0, &H2A, &H10, &H0, &H28, &H0, &H5, &H1, &H1, &H82, &H0, &HA, &H0, &H0, &H1}

            UdpMyClient.Send(cmd, cmd.Length)

            Dim response As Byte()
            Dim ep As New IPEndPoint(Target_IP, Target_Port)

            response = UdpMyClient.Receive(ep)

            For i = 0 To response.Count - 1
                Console.WriteLine(response(i))
            Next

            UdpMyClient.Close()

        Catch ex As Exception
            Console.WriteLine(ex)
        End Try


魔界の仮面弁士様のアドバイスを元に改良してみてBinary Writerを使うプログラムを試したのですがDim stream As New NetworkStream(MyUdpClient.Client, True) の部分で  
"ストリームに方向づけられていないソケットでは実行できない操作です。"
と例外が発生します。色々探しては見たのですが、見つけることができませんでした。何かアドバイス頂けないでしょうか?
プログラムを途中まで記載させていただきます。

  Try
            Dim MyUdpClient As New UdpClient
            Dim Target_IP As IPAddress = IPAddress.Parse("133.113.0.42")
            Dim Target_Port As Integer = 8000

            MyUdpClient.Client.ReceiveTimeout = 1000
            MyUdpClient.Client.SendTimeout = 1000
            Dim cmd As Byte() = {&H80, &H0, &H2, &H0, &H2A, &H10, &H0, &H28, &H0, &H5, &H1, &H1, &H82, &H0, &HA, &H0, &H0, &H1}

            MyUdpClient.Connect(Target_IP, Target_Port)
            Dim stream As New NetworkStream(MyUdpClient.Client, True)

            Dim writer As BinaryWriter = New BinaryWriter(Stream)
                         ///////////以下省略///////////////
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2017/9/26 00:08:08
> Dim Target_IP As IPAddress = IPAddress.Parse("133.113.0.42")
…東芝?


> Binary Writerを使うプログラムを試したのですが
BinaryWriter はストリームに書き込みを行うためのクラスです。
しかし今回はそのストリームがありません。
先の回答でも、「GetSream を解さずに」と書いていますよね。
(とはいえご存知のようにそもそも GetSream というメンバーは無いのですが)


> Dim stream As New NetworkStream(MyUdpClient.Client, True) の部分で  
私が NetworkStream を例示したのは、TCP の方だったハズ。
先の発言は『Client プロパティから基の Socket を取り出して使用する』案を提示したものです。
(ちなみに UdpClient.Send は、内部的には .Client.Send/SendTo 相当の処理を行っています)

UDP はそもそもストリーム指向のプロトコルでは無いでしょうし、先の回答も
TCPClient を真似てストリームとして扱うことを提案したわけではありません。
TCP であれ UDP であれ、元になっているのは Socket クラスであることを
紹介したかっただけなのですが…誤解させてしまったようですね。


> "ストリームに方向づけられていないソケットでは実行できない操作です。"
NetworkStream として開くためには、Socket クラスの SocketType プロパティが
Stream でなければなりません(かつブロッキングモードであること)。しかしながら、
TcpClient の方のソケットがストリーム(SocketType.Stream)であるのに対し、
UcpClient の方のソケットはデータグラム(SocketType.Dgram)となっています。

※ UDP = ユーザー データグラム プロトコル
投稿者 ポムNNN  (社会人) 投稿日時 2017/9/26 22:12:46
魔界の仮面弁士様

このたびは色々アドバイスありがとうございました。まだまだVBの知識が少なく勘違いすることがありご迷惑をおかけしました。もっと勉強いたします。

なんとなくお気づきでしょうが、PLCとイーサネットでつなぎデータの読み書きをしようと思っていました。
ちなみにメーカはオムロンです。
投稿者 daive  (社会人) 投稿日時 2017/9/27 20:31:21
他所でも、他の方の似たような質問があがっていましたが(流行りなのかな?)、
(teratail?わんくま?どっちだったけかな)
質問者さんでは無く、他の方の場合は、
自作は無理とは言いませんが、
掲示板で質問あげる、レベルの方には荷が重いかも。

業務用途では、工数削減他のために、
メーカー製ツールを使います。
PLCとの通信は、メーカー製サポートツール、SCADAを買った方が楽ができます。
趣味の範囲であれば、素人自作でも良いですが、
業務用途では、責任が問われかねないので、通信系の自作は御勧めしません。
(メーカー製ツールを何故使わなかったのか?とか、突っ込まれても大丈夫な方は除外)

パソコン対応の、Visual Studio通信サポートは、
OMRON SYSMACであれば、
CX-Compolet :昔つかったきりで、この数年は使ってない。
MELSECであれば、
MX Component:必要な都度、新バージョン購入。
になるはずです。検索してみてください。
MX Componentは、OS依存、Visual Studio バージョン依存がありますので、
旧バージョンの、開発用での保持は必須です。
また、
FA-Panel 等SCADAは、各社PLCとの接続が可能で、
Visual Studio と連携可能な物もあります。
(FA Panel / Intouch 等、Wizcon)
各社隠しコマンドがあるようで、
解析してドライバがあるのは、FA-Panel/PA-Panel/BA-Panel他
キーエンスのPLC(KV/KVnano)などは、かなり面白いのですが、
FA-Panelならば、USB/COM/TCP用ドライバがあったりします。
※但し、ScriptはVB風の癖のある、Script、
  昔から素直なのは、IntouchのScriptですが、こちらも、VB風

私自身は、PC-PLC:TCP/UDP/COM用も書いていますし、
Arduino 他マイコン用も書いています。
ので、きちんと勉強すれば、動く物を作る事は可能。
投稿者 ポムNNN   (社会人) 投稿日時 2017/9/29 20:51:18
daive様
興味深い情報ありがとうございます。
普段、PLCしか触っていないので、息抜き程度に始めた趣味なので業務使用はしないと思います。
データはタッチパネルからの変更ですし、自作アプリのバグで機械破損させてらシャレにならないので・・・・。
難しかったですが、久しぶりに熱中できるものを見つけて、VBって面白いなって思ってます。