前言
本文將使用一個Github公開的組件技術來實現一個異形ModBus TCP的客戶端,方便的對異形Modbus tcp的服務器進行讀寫,這個服務器可以是電腦端C#設計的,也可以是特殊設備實現的,也可以是其他任何支持這個通信協議的服務器。
github地址:https://github.com/dathlin/HslCommunication 如果喜歡可以star或是fork,還可以打賞支持。
本文下面的DEMO的項目的源代碼都在這個地址里面
聯系作者及加群方式(激活碼在群里發放):http://www.hslcommunication.cn/Cooperation
在Visual Studio 中的NuGet管理器中可以下載安裝,也可以直接在NuGet控制台輸入下面的指令安裝
Install-Package HslCommunication
NuGet安裝教程 http://www.cnblogs.com/dathlin/p/7705014.html
組件API地址:http://www.cnblogs.com/dathlin/p/7703805.html
關於異形模式,也叫偵聽式客戶端
通常的模式都是服務器客戶端模式,由客戶端發起連接,然后和服務器進行數據交換實現的,但是實際中還有一種模式就是,由服務器主動發起對客戶端的連接,然后客戶端再執行對服務器的數據交互,聽着可能會有些別扭,但是確實存在的,通常應用於一些,工業現場的4G上網的設備。當然也可以實現自定義的一些功能操作。需要慢慢的看下面的代碼。
異形模式主要分兩部分組成,偵聽服務器,異形modbus-tcp客戶端。
偵聽服務器負責,偵聽網絡請求和Alien協議驗證,通過之后將連接拋給異形modbus-tcp客戶端使用。
注冊包及Alien協議
在modbus服務器連上雲服務器的ip及端口地址后,需要發送一條注冊包信息,這條注冊包信息需要遵循如下的協議,稱為Alien協議,其他的協議支持需要二次定制開發完成。本協議詳細如下:
注冊包共28個字節,
// 注冊包
0x48 0x73 0x6E 0x00 0x17 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x30 0x31 0x00 0x00 0x00 0x00 0x00 0x00 0xC0 0xA8 0x00 0x01 0x17 0x10
+------------------+ +----+ +-----+ +-----------------------------------------------------------------------------+ +----------------------------------------+ +---------------------------+ +-------------+
+ 固定消息頭 + 備用 后面長度 DTU碼 12345678901 (唯一標識,比如手機號) 登錄密碼(不受信的排除) Ip:192.168.0.1 端口10000
+------------------+ +----+ +-----+ +----------------------------------------------------------------------------+ +-----------------------------------------+ +-------------------------+ +--------------+
// 返回消息,下面是正常的注冊成功的信息
0x48 0x73 0x6E 0x00 0x01 0x00
+----------------- + +----+ +----+ +----+
固定消息頭 備用 后面長度 結果代碼
// 結果代碼
0x00: 登錄成功
0x01: DTU重復登錄
0x02: DTU禁止登錄
0x03: 密碼驗證失敗
偵聽請求
第一步需要先建立偵聽服務器,觸發的事件為什么會有兩個參數是因為當你有多個服務器的時候,就可以共同關聯一個方法,然后通過network來區分信號,核心代碼如下所示,到時候只要調用 NetworkAlienStart 方法即可
private NetworkAlienClient networkAlien = null; private void NetworkAlienStart( int port ) { networkAlien = new NetworkAlienClient( ); networkAlien.OnClientConnected += NetworkAlien_OnClientConnected; networkAlien.LogNet = logNet; networkAlien.ServerStart( port ); } private void NetworkAlien_OnClientConnected( NetworkAlienClient network , AlienSession session ) { // 當有連接的時候會觸發這個方法 }
異形Modbus-Tcp
建立一個異形客戶端,數據交互塊和,原來的客戶端幾乎是一模一樣的,僅僅是連接原理不一樣,設置成異形客戶端之后,就不在負責連接的功能了,變成了被動設置連接對象的功能。代碼也是很方便的
1. 先定義對象
private ModbusTcpNet busTcpClient = null;
2. 實例化,IP和端口隨便指定,反正對於異形客戶端是沒有用途的,但是站號還是有用的
busTcpClient = new ModbusTcpNet( textBox1.Text, port, station );
3. 設置為異形模式,當然先不設置也可以,可以調到第四步再進行設置
busTcpClient.ConnectServer( null );
4. 修改請求偵聽的回調方法
private void NetworkAlien_OnClientConnected( NetworkAlienClient network, AlienSession session ) { busTcpClient.ConnectServer( session ); }
當有modbus服務器連接上來的時候,就觸發該方法,就可以通過busTcpClient對服務器進行數據讀寫了。上面演示的情況僅僅是一個客戶端的情況,如果有多個客戶端呢?我們可以通過唯一的識別碼來相互關聯,對於每個傳進來的session數據,還包含了連接請求的DTU唯一碼,我們就可以進行判定了。
我們先設置異形客戶端的唯一碼
busTcpClient.ConnectionId = "12345678901"
再修改回調方法
private void NetworkAlien_OnClientConnected( NetworkAlienClient network , AlienSession session ) { if(session.DTU == busTcpClient.ConnectionId) { busTcpClient.ConnectServer( session ); } }
通常的方法都是先定義好自己的客戶端數組,並指定DTU碼,然后批量的對數組進行數據請求操作。
具體的數據請求操作,請參照正常的Modbus-TCP博客,
http://www.cnblogs.com/dathlin/p/7885368.html
下面隨便貼一點示例代碼
private void userButton30_Click(object sender, EventArgs e) { // 讀取操作 bool coil100 = busTcpClient.ReadCoil("100").Content; // 讀取線圈100的通斷 short short100 = busTcpClient.ReadInt16("100").Content; // 讀取寄存器100的short值 ushort ushort100 = busTcpClient.ReadUInt16("100").Content; // 讀取寄存器100的ushort值 int int100 = busTcpClient.ReadInt32("100").Content; // 讀取寄存器100-101的int值 uint uint100 = busTcpClient.ReadUInt32("100").Content; // 讀取寄存器100-101的uint值 float float100 = busTcpClient.ReadFloat("100").Content; // 讀取寄存器100-101的float值 long long100 = busTcpClient.ReadInt64("100").Content; // 讀取寄存器100-103的long值 ulong ulong100 = busTcpClient.ReadUInt64("100").Content; // 讀取寄存器100-103的ulong值 double double100 = busTcpClient.ReadDouble("100").Content; // 讀取寄存器100-103的double值 string str100 = busTcpClient.ReadString("100", 5).Content;// 讀取100到104共10個字符的字符串 // 寫入操作 busTcpClient.WriteCoil("100", true);// 寫入線圈100為通 busTcpClient.Write("100", (short)12345);// 寫入寄存器100為12345 busTcpClient.Write("100", (ushort)45678);// 寫入寄存器100為45678 busTcpClient.Write("100", 123456789);// 寫入寄存器100-101為123456789 busTcpClient.Write("100", (uint)123456778);// 寫入寄存器100-101為123456778 busTcpClient.Write("100", 123.456);// 寫入寄存器100-101為123.456 busTcpClient.Write("100", 12312312312414L);//寫入寄存器100-103為一個大數據 busTcpClient.Write("100", 12634534534543656UL);// 寫入寄存器100-103為一個大數據 busTcpClient.Write("100", 123.456d);// 寫入寄存器100-103為一個雙精度的數據 busTcpClient.Write("100", "K123456789"); }
測試的Demo
如果感興趣,可以下載Demo測試,下載2個軟件,一個是服務器軟件,一個是客戶端軟件
先打開服務器,並啟動服務
再打開異形客戶端
設置好相關的參數后,啟動服務器,默認的參數如下,啟動成功的話,會彈出消息框【等待服務器的連接】
然后我們再回到服務器界面,點擊 連接異形客戶端 按鈕,彈出如下:然后將IP地址修改成本機的,端口改成剛剛在客戶端填寫的,ID和客戶端的一致
然后服務器界面彈框,連接成功。然后我們就可以回到客戶端界面進行數據讀寫的交互了。