FinsTCP
概略
FinsTCPの場合は最初に「FINS ノードアドレス情報送信コマンド」を送信してクライアントとサーバのFINSノードアドレスを取得します
取得したFINSノードアドレスをFINSヘッダにセットしてFINSフレームの前にFINS-TCPヘッダを付けて送信することになります
全体のメッセージは以下のようになります
FINS-TCPヘッダ | FINSフレーム | |||||||||||||||||||||||||||
Header | LEN | CMD | Err | FINSヘッダ | FINSコマンド | |||||||||||||||||||||||
'F' | 'I' | 'N' | 'S' |
ここではFinsTCPを使ってDMの値を読み出します

PLCのIPアドレス | 192.168.250.1 |
PCのIPアドレス | 192.168.250.48 |
送信コマンドの内容 | DM100から10CH分の値を読出す |
PLCのメモリの値
+0 | +1 | +2 | +3 | +4 | +5 | +6 | +7 | +8 | +9 | |
DM100 | 0001 | 0002 | 0003 | 0004 | 0005 | 0006 | 0007 | 0008 | 0009 | 000A |
以下サンプルコードは同期通信でのやり方をC#で書いてあります
フォームの作成(ボタンの配置など)は省略しているので適宜ボタンなどは配置してください
同期通信
受信タイムアウトは1000msとしているので1秒以内にレスポンスがなければ受信待ち状態から抜けます
private void TcpFinsMessage()
{
System.Net.Sockets.TcpClient tcp = new System.Net.Sockets.TcpClient("192.168.250.1", 9600);
System.Net.Sockets.NetworkStream ns = tcp.GetStream();
ns.ReadTimeout = 1000;
ns.WriteTimeout = 1000;
// FINS ノードアドレス情報送信コマンド
byte[] FinsTcpHeader = new byte[20];
FinsTcpHeader[0] = 0x46; // "F"
FinsTcpHeader[1] = 0x49; // "I"
FinsTcpHeader[2] = 0x4E; // "N"
FinsTcpHeader[3] = 0x53; // "S"
FinsTcpHeader[4] = 0x00;
FinsTcpHeader[5] = 0x00;
FinsTcpHeader[6] = 0x00;
FinsTcpHeader[7] = 0x0C;
FinsTcpHeader[8] = 0x00;
FinsTcpHeader[9] = 0x00;
FinsTcpHeader[10] = 0x00;
FinsTcpHeader[11] = 0x00;
FinsTcpHeader[12] = 0x00;
FinsTcpHeader[13] = 0x00;
FinsTcpHeader[14] = 0x00;
FinsTcpHeader[15] = 0x00;
FinsTcpHeader[16] = 0x00;
FinsTcpHeader[17] = 0x00;
FinsTcpHeader[18] = 0x00;
FinsTcpHeader[19] = 0x00;
ns.Write(FinsTcpHeader, 0, FinsTcpHeader.Length);
byte[] resHeader = new byte[256];
int resHeaderSize = ns.Read(resHeader, 0, resHeader.Length);
if ((resHeader[8] == 0x00 && resHeader[9] == 0x00) &&
(resHeader[10] == 0x00 && resHeader[11] == 0x01))
{
byte ClientNodeNo = resHeader[19];
byte ServerNodeNo = resHeader[23];
//FINS-TCPヘッダ+FINSフレームの送信
byte[] cmd = new byte[34];
// ----------------- FINS-TCPヘッダ
cmd[0] = 0x46; // "F"
cmd[1] = 0x49; // "I"
cmd[2] = 0x4E; // "N"
cmd[3] = 0x53; // "S"
cmd[4] = 0x00; // Length
cmd[5] = 0x00;
cmd[6] = 0x00;
cmd[7] = 18 + 8; // (Command以降のバイト数)
cmd[8] = 0x00; // Command
cmd[9] = 0x00;
cmd[10] = 0x00;
cmd[11] = 0x02;
cmd[12] = 0x00; // ErrorCode
cmd[13] = 0x00;
cmd[14] = 0x00;
cmd[15] = 0x00;
// ----------------- FINSヘッダ
cmd[16] = 0x80; // ICF
cmd[17] = 0x00; // RSV
cmd[18] = 0x02; // GCT
cmd[19] = 0; // DNA 相手先ネットワークアドレス
cmd[20] = ServerNodeNo; // DA1 相手先ノードアドレス
cmd[21] = 0; // DA2 相手先号機アドレス
cmd[22] = 0; // SNA 発信元ネットワークアドレス
cmd[23] = ClientNodeNo; // SA1 発信元ノードアドレス
cmd[24] = 0; // SA2 発信元号機アドレス
cmd[25] = 1; // SID 識別子 00-FFの任意の数値
// ----------------- FINSコマンド
cmd[26] = 0x01; // MRC 読出しコマンド 0101
cmd[27] = 0x01; // SRC
cmd[28] = 0x82; // MemoryType = DM
cmd[29] = 0x00; // ReadAddress = 100CH
cmd[30] = 0x64;
cmd[31] = 0x00;
cmd[32] = 0x00; // ReadSize = 10CH
cmd[33] = 0x0A;
ns.Write(cmd, 0, cmd.Length);
byte[] resCmd = new byte[2048];
int resCmdSize = ns.Read(resCmd, 0, resCmd.Length);
if ((resCmd[8] == 0x00 && resCmd[9] == 0x00) &&
(resCmd[10] == 0x00 && resCmd[11] == 0x02))
{
byte[] rcvData = new byte[resCmdSize];
Array.Copy(resCmd, rcvData, resCmdSize);
textBox1.AppendText(BitConverter.ToString(rcvData) + "\r\n");
}
}
ns.Close();
tcp.Close();
}
3-4行目
System.Net.Sockets.TcpClient tcp = new System.Net.Sockets.TcpClient("192.168.250.1", 9600);
System.Net.Sockets.NetworkStream ns = tcp.GetStream();
PCのIPアドレスとTCPポートNoを指定してTCPクライアントを作成します
データ送受信で使用するネットワークストリームをGetStreamで作成します
6-7行目
ns.ReadTimeout = 1000;
ns.WriteTimeout = 1000;
読み取りと書き込みのタイムアウト時間を1000msに設定します
9-30行目
// FINS ノードアドレス情報送信コマンド
byte[] FinsTcpHeader = new byte[20];
FinsTcpHeader[0] = 0x46; // "F"
~
FinsTcpHeader[19] = 0x00;
FINSノードアドレス情報送信コマンドを送信するバイト配列にセットします
FINS/TCPでは空いているFINSノードアドレスを取得するためにこのコマンドを送信します
詳しくはFINS/UDPとFINS/TCPの比較を参照してください
32行目
ns.Write(FinsTcpHeader, 0, FinsTcpHeader.Length);
FINSノードアドレス情報送信コマンドを送信します
34-35行目
byte[] resHeader = new byte[256];
int resHeaderSize = ns.Read(resHeader, 0, resHeader.Length);
FINSノードアドレス情報送信コマンドに対するレスポンスを受信します
37-38行目
if ((resHeader[8] == 0x00 && resHeader[9] == 0x00) &&
(resHeader[10] == 0x00 && resHeader[11] == 0x01))
レスポンスのFINS/TCPヘッダのCommandの項目の値が0x00000001のときに処理を進めます
41-42行目
byte ClientNodeNo = resHeader[19];
byte ServerNodeNo = resHeader[23];
レスポンスの19byte目を発信元(Client)ノード番号、23byte目を相手先(server)ノード番号として格納します
45-83行目
//FINS-TCPヘッダ+FINSフレームの送信
byte[] cmd = new byte[34];
// ----------------- FINS-TCPヘッダ
cmd[0] = 0x46; // "F"
~
cmd[33] = 0x0A;
FINS-TCPヘッダを含んでFINSコマンドを送信用バイト配列にセットします
ここではDM100から10CH分のデータを読み出すコマンドをセットしています
FINSコマンドの内容についてはFINSコマンドを参照してください
85行目
ns.Write(cmd, 0, cmd.Length);
FINSコマンドを送信します
87-88行目
byte[] resCmd = new byte[2048];
int resCmdSize = ns.Read(resCmd, 0, resCmd.Length);
FINSコマンドに対するレスポンスを受信します
90-97行目
if ((resCmd[8] == 0x00 && resCmd[9] == 0x00) &&
(resCmd[10] == 0x00 && resCmd[11] == 0x02))
{
byte[] rcvData = new byte[resCmdSize];
Array.Copy(resCmd, rcvData, resCmdSize);
textBox1.AppendText(BitConverter.ToString(rcvData) + "\r\n");
}
レスポンスのFINS/TCPヘッダのCommandの項目の値が0x00000002のときにレスポンスデータをrcvDataに格納してテキストボックス(txtBox1)に追加書込みします
99-1000行目
ns.Close();
tcp.Close();
ネットワークストリームとTCPクライアントのインスタンスを破棄します
サンプルソース

GitHubからここで紹介したソースがダウンロードできます