HOME ダウンロードに戻る

VB.NET, C# のサンプルソフト
 
リモートI/O装置と通信制御するサンプルプログラムを紹介します。
プログラムは特別なOCXを必要とすることなく動作する汎用的なものです。
 
プログラムの仕様は、VB.NET、C# とも同じです。
通信実行のタイミングを司るタイマーTimer1_Tick()と通信を司るkaracrix_com()から構成されています。
Timer1_Tick()では、通信相手のIPアドレスと送信コマンドを設定しkaracrix_com()を呼びます。
そして、通信で得られたデータをテキストボックスに表示させています。※テキストボックスはご用意下さい。
karacrix_com() では、UDPプロトコルを使ってエラー処理しながら通信制御しています。
 
 
 VB.NET
 
 
Imports System
Imports System.Text

Imports System.Net
Imports System.Net.Sockets

Public Class Form1

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    Timer1.Start()
    End Sub

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Dim rcvdatas    As Integer
        Dim ip          As String
        Dim cmd         As String
        Dim rcvdata(32) As String   REM 応答データ格納数

        REM IPアドレスにコマンドを送ると応答データがrcvdataの配列に格納されます。
        REM データの数はrcvdatasより得られます。rcvdatasが0の場合は通信エラーが生じた事を意味します。
        REM TK0040A機の場合、dinコマンド送ると、rcvdata(0)に応答コマンド"DIN"が、
        REM rcvdata(1)にデジタル入力データ"000111"(例)が、rcvdata(2)にデジタル出力データ"0011"(例)が格納されます。
        REM シーケンスIDはkaracrix_com内で追加削除され処理されていますのでこのレベルで意識する必要はありません。
        REM 通信条件はkaracrix_com内で以下の様に取り敢えず定義しています。通信環境に合わせ変更してください。
        REM rmt_port   = 20000  リモートI/O装置のポート番号でデフォルト値です。
        REM my_port    = 30000  PC側のポート番号で同じPC上の他のプログラムで同値を使わないよう注意してください。
        REM retrys     = 5      通信エラー時のリトライ回数で通信環境の悪い場合には回数を増やしてください。
        REM rcvtimeout = 8000   受信タイムアウト時間(msec)です。同一LAN内の場合3000、無線LANが経路に入っている
        REM                     場合タイムアウト時間を短くすると問題起きる場合ありますので10000ぐらいが良いです。

        ip  = "192.168.0.200"
        cmd = "hello"
        cmd = "din"
        cmd = "ain"
        cmd = "mix"
        rcvdatas = karacrix_com(sender, e, ip, cmd, rcvdata)
        TextBox1.Text = rcvdata(0)
        TextBox2.Text = rcvdata(1)
        TextBox3.Text = rcvdata(2)
        TextBox4.Text = rcvdata(3)
        TextBox5.Text = rcvdata(4)
        TextBox6.Text = rcvdata(5)
        TextBox7.Text = rcvdata(6)
        TextBox8.Text = rcvdata(7)
        TextBox9.Text = rcvdata(8)

    End Sub

    Function karacrix_com(ByVal sender As System.Object, ByVal e As System.EventArgs, ByVal ip As String, ByVal cmd As String, ByVal rcvdata() As String) As Integer
        Dim i, n, cnt           As Integer
        Dim retrys, rcvtimeout  As Integer
        Dim my_port, rmt_port   As Integer
        Dim rmt_ip, seqstr      As String
        Dim sndtext, rcvtext    As String
        Static seqcnt           As Integer = 1       REM seqcntは静的変数で使用

        Dim rescmd As String = ""                    REM チェックする応答コマンド文字を送信コマンド文より得ておく
        Dim splitcmd As String() = cmd.Split(" "c)   REM 送信コマンド文分析
        n = 0
        For Each word As String In splitcmd
            If word <> "" Then
                rescmd = word.ToUpper()              REM 応答コマンドは大文字仕様
                n = 1
            End If
            If n = 1 Then                            REM 最初の文字が送信コマンドのはず
                Exit For
            End If
        Next word
        If rescmd = "" Then Return 0                 REM 送信コマンド無し(エラー)

        seqcnt = 1 + seqcnt
        If seqcnt > 9999 Then seqcnt = 1

        REM rmt_ip = "192.168.0.200"
        rmt_ip     = ip
        rmt_port   = 20000                           REM リモート装置ポート番号
        my_port    = 30000                           REM PC側のポート番号
        retrys     = 5                               REM 通信エラー時のリトライ回数
        rcvtimeout = 8000                            REM 受信タイムアウト時間(msec)

        Dim udp As UdpClient  = Nothing
        Dim udpuse As Integer = 0

        For n = 1 To retrys

            seqstr  = Convert.ToString(seqcnt, 10)   REM シーケンスIDを文字に変換
            sndtext = seqstr + " " + cmd             REM 送信コマンド文にシーケンスIDを前置する

            Try
                REM 以下 MSDN .NET Framework Developer Center 参考
                udp    = New UdpClient(my_port)      REM ここでコンストラクトさせるとポートゴミが都度取り除ける
                udpuse = 1
                udp.Client.ReceiveTimeout = rcvtimeout
                Dim RemoteIpEndPoint As New IPEndPoint(IPAddress.Any, 0)    REM 受付IP無指定
                Dim sndbytes As [Byte]() = Encoding.ASCII.GetBytes(sndtext)
                udp.Send(sndbytes, sndbytes.Length, rmt_ip, rmt_port)       REM コマンド文送信
                Dim rcvbytes As [Byte]() = udp.Receive(RemoteIpEndPoint)    REM 応答受信:タイムアウト時例外処理へ
                Dim rcvstring As String = Encoding.ASCII.GetString(rcvbytes)
                rcvtext = rcvstring.ToString()
                REM TextBox0.Text = rcvtext                                 rem 受信データの表示
                Dim splitrcv As String() = rcvtext.Split(" "c)              REM 応答データの分割
                Dim rcvword(128) As String
                Dim rcvwords As Integer = 0
                For Each word As String In splitrcv
                    If word <> "" Then
                        rcvword(rcvwords) = word         REM 分割データを配列に格納
                        rcvwords = 1 + rcvwords
                    End If
                Next word
                udp.Close()                              REM ポート停止
                udpuse = 0
                If seqstr = rcvword(0) Then              REM 応答シーケンスIDのチェック
                    If rescmd = rcvword(1) Then          REM 応答コマンドのチェック
                        rcvwords = rcvwords - 1          REM 応答シーケンスIDは除く
                        cnt = 0
                        For i = 1 To rcvwords
                            rcvdata(cnt) = rcvword(i)
                            cnt = 1 + cnt
                        Next i
                        Return rcvwords                  REM 通信成功
                    End If
                End If
                System.Threading.Thread.Sleep(8000)      REM 同期通信失敗時数秒待機
                seqcnt = 1 + seqcnt                      REM 再送時はシーケンスID変更(遅延パケット識別用)
            Catch err As Exception
                REM TextBox0.Text = err.ToString()       rem エラー表示
            Finally
                If udpuse = 1 Then
                    udp.Close()
                    udpuse = 0
                End If
            End Try
        Next
        Return 0                                         REM 通信失敗
    End Function

End Class
 
 
 C#
 
 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Net;
using System.Net.Sockets;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        static int seqcnt = 1;        //クラス変数(静的変数)

        public Form1()
        {
            InitializeComponent();
            timer1.Tick += new EventHandler(timer1_Tick);
            timer1.Start();    // .or. timer1.Enabled = true;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            int    rcvdatas;
            String ip;
            String cmd; 
            String[] rcvdata = new string[32];  //応答データ格納数

         // IPアドレスにコマンドを送ると応答データがrcvdataの配列に格納されます。
         // データの数はrcvdatasより得られます。rcvdatasが0の場合は通信エラーが生じた事を意味します。
         // TK0040A機の場合、dinコマンド送ると、rcvdata(0)に応答コマンド"DIN"が、
         // rcvdata(1)にデジタル入力データ"000111"(例)が、rcvdata(2)にデジタル出力データ"0011"(例)が格納されます。
         // シーケンスIDはkaracrix_com内で追加削除され処理されていますのでこのレベルで意識する必要はありません。
         // 通信条件はkaracrix_com内で以下の様に取り敢えず定義しています。通信環境に合わせ変更してください。
         // rmt_port   = 20000  リモートI/O装置のポート番号でデフォルト値です。
         // my_port    = 30000  PC側のポート番号で同じPC上の他のプログラムで同値を使わないよう注意してください。
         // retrys     = 5      通信エラー時のリトライ回数で通信環境の悪い場合には回数を増やしてください。
         // rcvtimeout = 8000   受信タイムアウト時間(msec)です。同一LAN内の場合3000、無線LANが経路に入っている
         //                     場合タイムアウト時間を短くすると問題起きる場合ありますので10000ぐらいが良いです。

            ip  = "192.168.0.200";
            cmd = "hello";
            cmd = "din";
            cmd = "ain";
            cmd = "mix";
            rcvdatas = karacrix_com( sender, e, ip, cmd, rcvdata );
            textBox1.Text = rcvdata[0];
            textBox2.Text = rcvdata[1];
            textBox3.Text = rcvdata[2];
            textBox4.Text = rcvdata[3];
            textBox5.Text = rcvdata[4];
            textBox6.Text = rcvdata[5];
            textBox7.Text = rcvdata[6];
            textBox8.Text = rcvdata[7];
            textBox9.Text = rcvdata[8];
     
        }

        private int karacrix_com(object sender, EventArgs e, String ip, String cmd, String[] rcvdata)
        {
            int    i,n,cnt;
            int    retrys,rcvtimeout;
            int    my_port,rmt_port;
            String rmt_ip,seqstr;
            String sndtext,rcvtext;

            String rescmd = null;               //チェックする応答コマンド文字を送信コマンド文より得ておく
            String[] splitcmd = cmd.Split(' '); //送信コマンド文分析
            n = 0;
            foreach (String word in splitcmd)
            {
                if (word != "")
                {
                    rescmd = word.ToUpper();   //応答コマンドは大文字仕様
                    n = 1; 
                }
                if (n == 1) break;             //最初の文字が送信コマンドのはず
            }
            if (rescmd == null) return 0;      //送信コマンド無し(エラー)


            if ( ++seqcnt > 9999 ) seqcnt = 1; //seqcntはクラス変数(static)で使用

            //rmt_ip   = "192.168.0.200";
            rmt_ip     = ip;
            rmt_port   = 20000;                //リモート装置ポート番号
            my_port    = 30000;                //PC側のポート番号
            retrys     = 5;                    //通信エラー時のリトライ回数
            rcvtimeout = 8000;                 //受信タイムアウト時間(msec)

            UdpClient udp = null;

            for(n=0;n<retrys;n++){

              seqstr  = Convert.ToString(seqcnt, 10); //シーケンスIDを文字に変換
              sndtext = seqstr + " " + cmd;           //送信コマンド文にシーケンスIDを前置する

              try
              {
                // 以下 MSDN .NET Framework Developer Center 参考
                udp = new UdpClient(my_port);        //ここでコンストラクトさせるとポートゴミが都度取り除ける
                udp.Client.ReceiveTimeout = rcvtimeout;
                IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0); //受付IP無指定
                Byte[] sndbytes = Encoding.ASCII.GetBytes(sndtext);
                udp.Send(sndbytes, sndbytes.Length, rmt_ip, rmt_port);   //コマンド文送信
                Byte[] rcvbytes = udp.Receive(ref RemoteIpEndPoint);     //応答受信:タイムアウト時例外処理へ
                String rcvstring = Encoding.ASCII.GetString(rcvbytes);
                rcvtext = rcvstring.ToString();
                //textBox0.Text = rcvtext;                         //受信データの表示
                String[] splitrcv = rcvtext.Split(' ');            //応答データの分割
                String[] rcvword = new String[128];
                int      rcvwords = 0;
                foreach (String word in splitrcv)
                {
                  if( word != "" ) rcvword[rcvwords++] = word;     //分割データを配列に格納
                }
                udp.Close();                                       //ポート停止
                udp = null;
                if (seqstr == rcvword[0])                          //応答シーケンスIDのチェック
                {
                    if (rescmd == rcvword[1])                      //応答コマンドのチェック
                    {
                      rcvwords--;                                  //応答シーケンスIDは除く
                      for (i = 1, cnt = 0; i <= rcvwords; i++){
                         rcvdata[cnt++] = rcvword[i];
                      }
                      return rcvwords;                //通信成功
                    }
                }
                System.Threading.Thread.Sleep(8000);  //同期通信失敗時数秒待機
                seqcnt++;                            //再送時はシーケンスID変更(遅延パケット識別用)
              }
              catch (Exception err)
              {
                //textBox0.Text = err.ToString();     //エラー表示
              }
              finally{
                  if (udp != null)
                  {
                      udp.Close();
                      udp = null;
                  }
              }

            }
            return 0;                                //通信失敗
        }
    }
}



//MainProgram.cs 以下参考
-----------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}
-----------------------------------------------------------------


HOME