目       錄

6. 并發(fā)通訊模式開發(fā)及注意事項... 2

6.1           概述... 2

6.2           通訊機(jī)制說明... 2

6.3           設(shè)備驅(qū)動開發(fā)注意事項... 3

6.3.1    實時發(fā)送數(shù)據(jù)... 3

6.3.2    優(yōu)先發(fā)送其他數(shù)據(jù)... 3

6.3.3    如何選擇IO通道發(fā)送數(shù)據(jù)... 4

6.3.4    如何以DeviceCode分配數(shù)據(jù)... 4

6.4           宿主程序服務(wù)實例配置注意事項... 5

6.5           并發(fā)模式運行效果... 6

 

6. 并發(fā)通訊模式開發(fā)及注意事項  

6.1    概述

     并發(fā)通訊模式只能用于網(wǎng)絡(luò)通訊設(shè)備,主要是加強(qiáng)通訊的并發(fā)能力,集中發(fā)送請求數(shù)據(jù),異步接收返回數(shù)據(jù)。集中發(fā)送請求數(shù)據(jù)的間隔時間可以設(shè)置;異步接收返回數(shù)據(jù)涉及到如何分配數(shù)據(jù)到相應(yīng)的設(shè)備驅(qū)動的問題,主要是通過兩種方式:IP地址的方式和設(shè)備Code的方式,前者適用于設(shè)備終端是固定IP地址的情況,后者適用于設(shè)備終端是動態(tài)IP的情況,例如:DTU、GPRS、3G/4G等無線通訊方式。

     并發(fā)通訊模式本質(zhì)上還是呼叫應(yīng)答的通訊方式,與輪詢通訊模式類似,但是比輪詢通訊模式的采集數(shù)據(jù)更高效。

6.2    通訊機(jī)制說明

     網(wǎng)絡(luò)通訊的情況下,輪詢模式顯然效率比較低,那么可以采用并發(fā)模式。并發(fā)通訊模式是集中發(fā)送給所有設(shè)備請求指令,框架是采用循環(huán)同步方式發(fā)送請求命令給每個IO通道對應(yīng)的設(shè)備,當(dāng)然也可以采用并行異步方式集中發(fā)送請求命令。硬件設(shè)備接收到指令后進(jìn)行校驗,校驗成功后返回對應(yīng)指令的數(shù)據(jù),通訊平臺異步監(jiān)聽到數(shù)據(jù)信息后,進(jìn)行接收操作,然后再進(jìn)行數(shù)據(jù)的分發(fā)、處理等。

     那么這里就涉及到IO通道接收到的數(shù)據(jù)是異步接收的,如何才能和設(shè)備驅(qū)動匹配上(把數(shù)據(jù)分發(fā)到設(shè)備驅(qū)動上),這是能過DeviceCode和DeviceIP兩種方式來實現(xiàn)的。DeviceCode可以是設(shè)備地址或是設(shè)備編碼,DeviceIP是預(yù)先設(shè)置好的參數(shù),要求終端設(shè)備的IP地址是固定的。

     通訊結(jié)構(gòu)如下圖:

`大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計算培訓(xùn),高端軟件開發(fā)培訓(xùn),項目經(jīng)理培訓(xùn)

6.3    設(shè)備驅(qū)動開發(fā)注意事項

6.3.1    實時發(fā)送數(shù)據(jù)

     ServerSuperIO框架會輪詢調(diào)度所有設(shè)備,以呼叫應(yīng)答的方式向設(shè)備發(fā)送請求實時數(shù)據(jù)命令,對于同一個設(shè)備的請求實時數(shù)據(jù)命令一般相對固定。在調(diào)度某一具體設(shè)備驅(qū)動的時候,會調(diào)用固定的調(diào)用IRunDevice驅(qū)動接口的GetConstantCommand函數(shù),以獲得請求實時數(shù)據(jù)的命令。代碼如下:

1
2
3
4
5
6
7
public override byte[] GetConstantCommand()
 {
     byte[] data = this.Protocol.DriverPackage<String>("0""61"null);
     string hexs = BinaryUtil.ByteToHex(data);
     OnDeviceRuningLog("發(fā)送>>"+hexs);
     return data;
 }

     this.Protocol.DriverPackage驅(qū)動調(diào)用61命令獲得要發(fā)送的命令,并返回byte[]數(shù)組,ServerSuperIO獲得數(shù)據(jù)后會自動通過IO接口下發(fā)命令數(shù)據(jù)。如果返回null類型,系統(tǒng)不進(jìn)行下發(fā)操作。

6.3.2    優(yōu)先發(fā)送其他數(shù)據(jù)

對于一個設(shè)備不可能只有一個讀實時數(shù)據(jù)的命令,可能還存在其他命令進(jìn)行交互,例如:讀參數(shù)、實時校準(zhǔn)等,這時就需要進(jìn)行優(yōu)先級調(diào)度發(fā)送數(shù)據(jù)信息??梢酝ㄟ^兩種方式讓ServerSuperIO框架優(yōu)先調(diào)度該設(shè)備驅(qū)動。

  1. 把命令增加發(fā)送數(shù)據(jù)緩存中,框架從緩存中獲得數(shù)據(jù)后會自動刪除,代碼如下:

1
this.Protocol.SendCache.Add("讀參數(shù)",readParaBytes);

      2.設(shè)置設(shè)備的優(yōu)先級別屬性,代碼如下:

1
this.DevicePriority=DevicePriority.Priority;

6.3.3    如何選擇IO通道發(fā)送數(shù)據(jù)

     集中發(fā)送數(shù)據(jù)時,涉及到如何關(guān)聯(lián)設(shè)備驅(qū)動與IO通道,框架會以DeviceParameter.NET.RemoteIP設(shè)置的終端IP參數(shù)進(jìn)行選擇IO通道發(fā)送數(shù)據(jù)。但是如果終端設(shè)備是動態(tài)IP地址的話,那么RemoteIP參數(shù)也應(yīng)該是變動的。這時就需要設(shè)置服務(wù)實例是以DeviceCode的方式分布數(shù)據(jù)到設(shè)備驅(qū)動,終端設(shè)備先發(fā)送簡單的驗證數(shù)據(jù),保證發(fā)送的DeviceCode與設(shè)備驅(qū)動的相對應(yīng),設(shè)備驅(qū)動接收到驗證數(shù)據(jù)后需要保存臨時的RemoteIP信息,這樣保證在發(fā)送數(shù)據(jù)的時候參數(shù)準(zhǔn)確找到要請求數(shù)據(jù)的IO通道到終端設(shè)備。

     例如下面代碼:

1
2
3
4
5
6
public override void Communicate(ServerSuperIO.Communicate.IRequestInfo info)
{
            this.DeviceParameter.NET.RemoteIP = info.Channel.Key;
            this.DeviceParameter.Save(this.DeviceParameter);
            ……
}

6.3.4    如何以DeviceCode分配數(shù)據(jù)

     如果服務(wù)實例設(shè)置以DeliveryMode.DeviceCode模式分配數(shù)據(jù),那么就需要在通訊協(xié)議接口里實現(xiàn)過濾DeviceCode編碼的接口。

     例如下面的代碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  internal class DeviceProtocol:ProtocolDriver
    {
        public override string GetCode(byte[] data)
        {
            byte[] head = new byte[] {0x55, 0xaa};
            int codeIndex = data.Mark(0, data.Length, head);
            if (codeIndex == -1)
            {
                return String.Empty;
            }
            else
            {
                return data[codeIndex + head.Length].ToString();
            }
        }
}

6.4    宿主程序服務(wù)實例配置注意事項

     在宿主程序中創(chuàng)建服務(wù)實例的時候,需要把服務(wù)實例的配置參數(shù)設(shè)置為并發(fā)通訊模式,并啟動服務(wù)實例,把實例化的設(shè)備驅(qū)動增加到該服務(wù)實例中。代碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
static void Main(string[] args)
{
            IServer server = new ServerFactory().CreateServer(new ServerConfig()
            {
                ServerName = "服務(wù)1",
                ComReadTimeout = 1000,
                ComWriteTimeout = 1000,
                NetReceiveTimeout = 1000,
                NetSendTimeout = 1000,
                ControlMode = ControlMode.Parallel,
                SocketMode = SocketMode.Tcp,
                StartReceiveDataFliter = false,
                ClearSocketSession = false,
                StartCheckPackageLength = false,
                CheckSameSocketSession = false,
                DeliveryMode = DeliveryMode.DeviceCode,
                ParallelInterval = 1000
            });
            server.AddDeviceCompleted += server_AddDeviceCompleted;
            server.DeleteDeviceCompleted += server_DeleteDeviceCompleted;
            server.Start();
 
            string devCode = "0";
            DeviceDriver dev1 = new DeviceDriver();
            dev1.DeviceParameter.DeviceName = "設(shè)備驅(qū)動"+ devCode.ToString();
            dev1.DeviceParameter.DeviceAddr = int.Parse(devCode);
            dev1.DeviceParameter.DeviceCode = devCode.ToString();
            dev1.DeviceParameter.DeviceID = devCode.ToString();
            dev1.DeviceDynamic.DeviceID = devCode.ToString();
            dev1.DeviceParameter.NET.RemoteIP = "127.0.0.1";
            dev1.DeviceParameter.NET.RemotePort = 9600;
            dev1.CommunicateType = CommunicateType.NET;
            dev1.Initialize(devCode.ToString());
            server.AddDevice(dev1);
 
            devCode = "1";
            DeviceDriver dev2 = new DeviceDriver();
            dev2.DeviceParameter.DeviceName = "設(shè)備驅(qū)動" + devCode.ToString();
            dev2.DeviceParameter.DeviceAddr = int.Parse(devCode);
            dev2.DeviceParameter.DeviceCode = devCode.ToString();
            dev2.DeviceParameter.DeviceID = devCode.ToString();
            dev2.DeviceDynamic.DeviceID = devCode.ToString();
            dev2.DeviceParameter.NET.RemoteIP = "192.168.1.102";
            dev2.DeviceParameter.NET.RemotePort = 9600;
            dev2.CommunicateType = CommunicateType.NET;
            dev2.Initialize(devCode.ToString());
            server.AddDevice(dev2);
 
            while ("exit" == Console.ReadLine())
            {
                server.Stop();
            }
}

    ControlMode = ControlMode. Parallel代碼是設(shè)置服務(wù)實例調(diào)度設(shè)備為并發(fā)控制模式;以DeliveryMode = DeliveryMode.DeviceCode方式進(jìn)行數(shù)據(jù)分發(fā),當(dāng)然我現(xiàn)在模擬的是因定的終端IP。

6.5    并發(fā)模式運行效果

1.圖片

 大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計算培訓(xùn),高端軟件開發(fā)培訓(xùn),項目經(jīng)理培訓(xùn)

2.視頻

 


 

1.[連載]《C#通訊(串口和網(wǎng)絡(luò))框架的設(shè)計與實現(xiàn)》

2.[開源]C#跨平臺物聯(lián)網(wǎng)通訊框架ServerSuperIO(SSIO)介紹

2.應(yīng)用SuperIO(SIO)和開源跨平臺物聯(lián)網(wǎng)框架ServerSuperIO(SSIO)構(gòu)建系統(tǒng)的整體方案

3.C#工業(yè)物聯(lián)網(wǎng)和集成系統(tǒng)解決方案的技術(shù)路線(數(shù)據(jù)源、數(shù)據(jù)采集、數(shù)據(jù)上傳與接收、ActiveMQ、Mongodb、WebApi、手機(jī)App)


延伸閱讀

唯笑志在-專注物聯(lián)網(wǎng)和系統(tǒng)集成建設(shè)【物聯(lián)網(wǎng)&集成技術(shù)-Java培訓(xùn),做最負(fù)責(zé)任的教育,學(xué)習(xí)改變命運,軟件學(xué)習(xí),再就業(yè),大學(xué)生如何就業(yè),幫大學(xué)生找到好工作,lphotoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動軟件開發(fā)培訓(xùn),網(wǎng)站設(shè)計培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)唯笑志在-專注物聯(lián)網(wǎng)和系統(tǒng)集成建設(shè)【物聯(lián)網(wǎng)&集成技術(shù)