C#实现欧姆龙 HostLink 通讯协议库

运行环境:VS2022 .net framework4.8

通讯库项目地址(Gitee):通讯库项目Gitee 仓库

控制台测试项目地址(Gitee):控制台测试项目Gitee 仓库

HostLink 通讯手册链接(蓝奏云):SYSMAC Series Communications Commands

官方的 HostLink 串口通讯示例(蓝奏云):C-Mode || FINS-Mode

通讯工具(蓝奏云):Commix 1.4

概要:根据欧姆龙的 HostLink 通讯协议手册内容,使用串口实现了 PC 与 PLC 的通讯,能够通过C-ModeFINS-Mode两种模式实现 PC 读写 PLC 的CIO、WR、HR、DM 四个内存区的内容(同步/异步方法),而且可以以较高的通讯效率获取所需数据、错误代码等信息,最后用一个 C#控制台项目测试了通讯库功能


背景介绍

HostLink 协议是欧姆龙 PLC 与主机通讯的一种公开协议,PC 可通过 HostLink 命令对 PLC 的运行状态、I/O 点位的读写

HostLink 分为 C-Mode 和 FINS-Mode 两种模式

C-Mode 命令是专门的主机链路通信命令,它们由主机发出并发送至 CPU 单元。可连接用于串行通信的设备有 CPU 单元、串行通信单元和串行通信板。

FINS-Mode 命令是报文服务通信命令,它们不依赖于特定的传输路径。它们可用于各种网络(控制器链路、以太网等)和串行通信(主机链路)。它们可以从 CPU 单元、特殊 I/O 单元或主机发出,也可以发送到其中任何一个单元。可发送的具体命令取决于目的地。

欧姆龙 PLC 内存区域介绍

内存区域名 区域说明
CIO I/O 继电器区
WR 内部辅助继电器区
HR 保持继电器区
DM 数据存储区
TIM 定时器区
CNT 计数器区
IR 变址寄存器区
DR 数据寄存器
AR 特殊辅助继电器区
TR 暂存区
TK 状态标志、时钟脉冲、任务标志

欧姆龙 PLC 数据类型对应

PLC 数据类型 PC 数据类型
Bit bool
Byte ushort
DWord uint
Int short
Dint int
float float
String string

欧姆龙 PLC 与 PC 的 RS232 接线线序


HostLink通讯报文分析

根据C-Mode和FINS的报文进行分析

C-Mode通讯报文分析

发送报文如下图所示

正常接收报文如下图所示

通讯出错接收报文如下图所示

使用串口工具Commix进行测试如下图所示

TS命令:



RD、WD命令:

FINS-Mode通讯报文分析

发送报文如下图所示

接收报文如下图所示

FINS指令配置如下图所示

使用串口工具Commix进行测试如下图所示

0101、0102命令:


HostLink通讯协议库的C#实现

核心实现(FCS校验码生成、串口收发)

HostLinkCore.cs

在这里我本来想给异步的方法加上一个SemaphoreSlim来限制通讯的信号量的,但是后来想了想还是让使用者在外面自己加好了:)

SemaphoreSlim具体的使用方法可以参考文章的C#控制台项目

/// <summary>
/// 通过命令帧计算FCS异或校验码并加上结束符
/// </summary>
/// <param name="CommandFrame">命令帧</param>
/// <returns>4位字节数组,包含FCS校验码与结束符</returns>
public static List<byte> HostLinkEndCode(List<byte> CommandFrame)
{
try
{
List<byte> EndCode = new List<byte>();
short FCSNum = HostLinkFCS(CommandFrame); string HexString = FCSNum.ToString("X2"); EndCode.AddRange(Encoding.ASCII.GetBytes(HexString));
EndCode.AddRange(new List<byte> { 0x2A, 0x0D });
return EndCode;
}
catch (Exception)
{
throw;
}
} /// <summary>
/// 对字节数组进行异或运算得到数值
/// </summary>
/// <param name="CommandFrame">命令帧</param>
/// <returns>异或运算结果(short类型)</returns>
public static short HostLinkFCS(List<byte> CommandFrame)
{
try
{
short CheckNum = 0;
foreach (byte FrameNum in CommandFrame)
{
CheckNum ^= FrameNum;
}
return CheckNum;
}
catch (Exception)
{
throw;
}
} /// <summary>
/// 检查回复帧是否完整
/// </summary>
/// <param name="frame">回复帧</param>
/// <returns>完整结尾:返回True;不完整:返回False</returns>
private static bool CheckResponseFrame(List<byte> frame)
{
if (frame.Count > 0 && frame[frame.Count - 1] == (byte)0x0D)
{
return true;
}
else
{
return false;
}
} /// <summary>
/// HostLink报文发送与接收代码
/// </summary>
/// <param name="serialPort">串口实例</param>
/// <param name="CommandFrame">命令帧</param>
/// <returns>回复帧</returns>
public static List<byte> HostLinkCommCore(SerialPort serialPort, List<byte> CommandFrame)
{
try
{
List<byte> ResponseFrame = new List<byte>(); //发送报文
serialPort.Write(CommandFrame.ToArray(), 0, CommandFrame.Count); //循环读取数据
while (serialPort.IsOpen)
{
if (serialPort.BytesToRead > 0)
{
byte[] buffer = new byte[serialPort.BytesToRead];
serialPort.Read(buffer, 0, buffer.Length); ResponseFrame.AddRange(buffer); if (CheckResponseFrame(ResponseFrame))
{
return ResponseFrame;
}
}
} return null;
}
catch (Exception)
{
throw;
}
} /// <summary>
/// HostLink报文发送与接收代码(异步方法)
/// </summary>
/// <param name="serialPort">串口实例</param>
/// <param name="CommandFrame">命令帧</param>
/// <returns>回复帧</returns>
public static async Task<List<byte>> HostLinkCommCoreAsync(SerialPort serialPort, List<byte> CommandFrame)
{
try
{
List<byte> ResponseFrame = new List<byte>(); //发送报文
await serialPort.BaseStream.WriteAsync(CommandFrame.ToArray(), 0, CommandFrame.Count); //循环读取数据
while (serialPort.IsOpen)
{
if (serialPort.BytesToRead > 0)
{
byte[] buffer = new byte[serialPort.BytesToRead];
await serialPort.BaseStream.ReadAsync(buffer, 0, buffer.Length); ResponseFrame.AddRange(buffer); if (CheckResponseFrame(ResponseFrame))
{
return ResponseFrame;
}
}
} return null;
}
catch (Exception)
{
throw;
}
}

C-Mode实现

CmodeEndCode.cs

/// <summary>
/// 对比回复帧中的EndCode,看内容是否相符
/// </summary>
/// <param name="ResponseFrame">回复帧</param>
/// <returns>返回结束代码</returns>
public static string CatchEndCode(List<byte> ResponseFrame, int EndCodeAdr)
{
try
{
List<byte> ResponseEndCode = ResponseFrame.GetRange(EndCodeAdr, 2);
string EndCodeContents = null; if (ResponseEndCode.SequenceEqual(new List<byte> { 0x30, 0x30 }))
{
EndCodeContents = "00";
}
else
{
foreach (var EndCodeMap in EndCodeMapSeq)
{
if (ResponseEndCode.SequenceEqual(EndCodeMap.Key))
{
EndCodeContents = EndCodeMap.Value;
break;
}
}
}
return EndCodeContents;
}
catch (Exception ex)
{
throw ex;
}
} private static readonly Dictionary<List<byte>, string> EndCodeMapSeq = new Dictionary<List<byte>, string>
{
{new List<byte> { 0x30, 0x31 },"EndCode: 01; Contents: Not executable in RUN mode" },
{new List<byte> { 0x30, 0x32 },"EndCode: 02; Contents: Not executable in MONITOR mode" },
{new List<byte> { 0x30, 0x33 },"EndCode: 03; Contents: UM write-protected" },
{new List<byte> { 0x30, 0x34 },"EndCode: 04; Contents: Address over" },
{new List<byte> { 0x30, 0x42 },"EndCode: 0B; Contents: Not executable in PROGRAM mode" },
{new List<byte> { 0x31, 0x33 },"EndCode: 13; Contents: FCS error" },
{new List<byte> { 0x31, 0x34 },"EndCode: 14; Contents: Format error" },
{new List<byte> { 0x31, 0x35 },"EndCode: 15; Contents: Entry number data error" },
{new List<byte> { 0x31, 0x36 },"EndCode: 16; Contents: Command not supported" },
{new List<byte> { 0x31, 0x38 },"EndCode: 18; Contents: Frame length error" },
{new List<byte> { 0x31, 0x39 },"EndCode: 19; Contents: Not executable" },
{new List<byte> { 0x32, 0x30 },"EndCode: 20; Contents: Could not create I/O table" },
{new List<byte> { 0x32, 0x31 },"EndCode: 21; Contents: Not executable due to CPU Unit CPU error" },
{new List<byte> { 0x32, 0x33 },"EndCode: 23; Contents: User memory protected" },
{new List<byte> { 0x41, 0x33 },"EndCode: A3; Contents: Aborted due to FCS error in trans-mission data" },
{new List<byte> { 0x41, 0x34 },"EndCode: A4; Contents: Aborted due to format error in transmission data" },
{new List<byte> { 0x41, 0x35 },"EndCode: A5; Contents: Aborted due to entry number data error in transmission data" },
{new List<byte> { 0x41, 0x38 },"EndCode: A8; Contents: Aborted due to frame length error in transmission data" }
};

CmodeHeaderCode.cs

internal class CmodeHeaderCode
{
public static readonly byte[] HeaderCode_RR = { 0x52, 0x52 };
public static readonly byte[] HeaderCode_RD = { 0x52, 0x44 };
public static readonly byte[] HeaderCode_WR = { 0x57, 0x52 };
public static readonly byte[] HeaderCode_WD = { 0x57, 0x44 };
public static readonly byte[] HeaderCode_TS = { 0x54, 0x53 };
public static readonly byte[] HeaderCode_MS = { 0x4D, 0x53 };
public static readonly byte[] HeaderCode_SC = { 0x53, 0x43 };
}

功能实现的代码过长,请自行到通讯库项目Gitee 仓库查看吧

FINS-Mode实现

定义一个FinsResult的类用来接收所需要的信息

(目前通信库反馈的大部分数据都是Bool与String列表,所以里面分开成两个Datas)

FinsResult.cs

/// <summary>
/// Fins通信结果类
/// </summary>
public class FinsResult
{
/// <summary>
/// FINS通信状态
/// </summary>
public bool IsSuccessed { get; set; } /// <summary>
/// FINS通信结果信息
/// </summary>
public string ResultMessage { get; set; } /// <summary>
/// 通信命令帧
/// </summary>
public string CommandFrame { get; set; } /// <summary>
/// 通信回复帧
/// </summary>
public string ResponseFrame { get; set; } /// <summary>
/// 数据列表(bool类型)
/// </summary>
public List<bool> Datas_BoolList { get; set; } /// <summary>
/// 数据列表(string类型)
/// </summary>
public string Datas_String { get; set; } /// <summary>
/// 完整构造函数
/// </summary>
/// <param name="isSuccessed">FINS通信状态</param>
/// <param name="resultMessage">FINS通信结果信息</param>
/// <param name="commandFrame">通信命令帧</param>
/// <param name="responseFrame">通信回复帧</param>
/// <param name="datas">数据列表</param>
public FinsResult(bool isSuccessed, string resultMessage, string commandFrame, string responseFrame, List<bool> datas1, string datas2)
{
IsSuccessed = isSuccessed;
ResultMessage = resultMessage;
CommandFrame = commandFrame;
ResponseFrame = responseFrame;
Datas_BoolList = datas1;
Datas_String = datas2;
} //五参数构造函数(带bool数据列表)
public FinsResult(bool isSuccessed, string resultMessage, string commandFrame, string responseFrame, List<bool> datas) :
this(isSuccessed, resultMessage, commandFrame, responseFrame, datas, null)
{ } //五参数构造函数(带string数据列表)
public FinsResult(bool isSuccessed, string resultMessage, string commandFrame, string responseFrame, string datas) :
this(isSuccessed, resultMessage, commandFrame, responseFrame, null, datas)
{ } //四参数构造函数(无数据反馈)
public FinsResult(bool isSuccessed, string resultMessage, string commandFrame, string responseFrame) :
this(isSuccessed, resultMessage, commandFrame, responseFrame, null, null)
{ } //两参数构造函数(出错时返回)
public FinsResult(bool isSuccessed, string resultMessage) : this(isSuccessed, resultMessage, null, null, null, null) { } }

通讯库定义了一些常用的内存区域枚举类,使用时可以提前设定好

FinsIOMemoryAreaAddress.cs

/// <summary>
/// FinsIO内存区域地址类
/// </summary>
public class FinsIOMemoryAreaAddress
{
/// <summary>
/// 内存区域代码
/// </summary>
public FinsMemoryAreaTypeEnum AreaType { get; set; } /// <summary>
/// Word起始地址
/// </summary>
public ushort WordAddress { get; set; } /// <summary>
/// Bit起始地址
/// </summary>
public ushort BitAddress { get; set; }
}

FinsMemoryAreaTypeEnum.cs

/// <summary>
/// Fins内存区域类型
/// </summary>
public enum FinsMemoryAreaTypeEnum
{
CIOBit,
CIOWord,
WRBit,
WRWord,
HRBit,
HRWord,
DMBit,
DMWord
}

FINS指令配置的代码如下

FinsFrameConfig.cs

public class FinsFrameConfig
{
public string ICF { get; set; }
public string RSV { get; set; }
public string GCT { get; set; }
public string DNA { get; set; }
public string DA1 { get; set; }
public string DA2 { get; set; }
public string SNA { get; set; }
public string SA1 { get; set; }
public string SA2 { get; set; }
public string SID { get; set; }
}

功能实现的代码过长,请自行到通讯库项目Gitee 仓库查看吧


C#控制台测试功能

HostLinkDevice.cs

public class HostLinkDevice
{
public HostLinkDevice(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits)
{
PLC = new HostLinkFinsDevice(portName, baudRate, parity, dataBits, stopBits);
} //HostLinkFins设备
private HostLinkFinsDevice PLC; //Fins帧参数设置
private static FinsFrameConfig finsFrameConfig = new FinsFrameConfig()
{
ICF = "00",
DA2 = "00",
SA2 = "00",
SID = "00"
}; /// <summary>
/// 串口打开
/// </summary>
public void Connect()
{
try
{
PLC.Connect();
}
catch (Exception)
{
throw;
}
} /// <summary>
/// 串口关闭
/// </summary>
public void Disconnect()
{
try
{
PLC.DisConnect();
}
catch (Exception)
{
throw;
}
} /// <summary>
/// 读取CIO区的连续Bit位方法(异步方法)
/// </summary>
/// <param name="WordAdr">读取起始Word地址</param>
/// <param name="BitAdr">读取起始Bit地址</param>
/// <param name="ReadCount">读取Bit位数量</param>
/// <returns>返回通信结果的信息</returns>
public async Task<List<bool>> ReadCIOBitAsync(ushort WordAdr, ushort BitAdr, ushort ReadCount)
{
try
{
FinsResult finsResult;
//IO内存区域设置
FinsIOMemoryAreaAddress IOMemoryAreaAdr = new FinsIOMemoryAreaAddress()
{
AreaType = FinsMemoryAreaTypeEnum.CIOBit,
WordAddress = WordAdr,
BitAddress = BitAdr
}; //获取FINS通信结果
finsResult = await PLC.Read_MemoryAreaAsync(IOMemoryAreaAdr, finsFrameConfig, ReadCount); if (finsResult.IsSuccessed)
{
if (finsResult.ResultMessage.Equals("OK"))
{
return finsResult.Datas_BoolList;
}
else
{
throw new Exception($"{finsResult.ResultMessage}{Environment.NewLine}{Environment.NewLine}发送命令帧:{finsResult.CommandFrame}{Environment.NewLine}接收回复帧:{finsResult.ResponseFrame}");
}
}
else
{
throw new Exception($"{finsResult.ResultMessage}{Environment.NewLine}{Environment.NewLine}发送命令帧:{finsResult.CommandFrame}{Environment.NewLine}接收回复帧:{finsResult.ResponseFrame}");
}
}
catch (Exception)
{
throw;
}
} /// <summary>
/// 读取W区的连续Bit位方法(异步方法)
/// </summary>
/// <param name="WordAdr">读取起始Word地址</param>
/// <param name="BitAdr">读取起始Bit地址</param>
/// <param name="ReadCount">读取Bit位数量</param>
/// <returns>返回通信结果的信息</returns>
public async Task<List<bool>> ReadWRBitAsync(ushort WordAdr, ushort BitAdr, ushort ReadCount)
{
try
{
FinsResult finsResult;
//IO内存区域设置
FinsIOMemoryAreaAddress IOMemoryAreaAdr = new FinsIOMemoryAreaAddress()
{
AreaType = FinsMemoryAreaTypeEnum.WRBit,
WordAddress = WordAdr,
BitAddress = BitAdr
}; //获取FINS通信结果
finsResult = await PLC.Read_MemoryAreaAsync(IOMemoryAreaAdr, finsFrameConfig, ReadCount); if (finsResult.IsSuccessed)
{
if (finsResult.ResultMessage.Equals("OK"))
{
return finsResult.Datas_BoolList;
}
else
{
throw new Exception($"{finsResult.ResultMessage}{Environment.NewLine}{Environment.NewLine}发送命令帧:{finsResult.CommandFrame}{Environment.NewLine}接收回复帧:{finsResult.ResponseFrame}");
}
}
else
{
throw new Exception($"{finsResult.ResultMessage}{Environment.NewLine}{Environment.NewLine}发送命令帧:{finsResult.CommandFrame}{Environment.NewLine}接收回复帧:{finsResult.ResponseFrame}");
}
}
catch (Exception)
{
throw;
}
} /// <summary>
/// 写入W区的连续Bit位方法(异步方法)
/// </summary>
/// <param name="WordAdr">写入起始Word地址</param>
/// <param name="BitAdr">写入起始Bit地址</param>
/// <param name="WriteCount">写入Bit位数量</param>
/// <param name="WriteData">写入数据</param>
/// <returns>返回通信结果的信息</returns>
public async Task<string> WriteWRBitAsync(ushort WordAdr, ushort BitAdr, ushort WriteCount, string WriteData)
{
try
{
FinsResult finsResult;
//IO内存区域设置
FinsIOMemoryAreaAddress IOMemoryAreaAdr = new FinsIOMemoryAreaAddress()
{
AreaType = FinsMemoryAreaTypeEnum.WRBit,
WordAddress = WordAdr,
BitAddress = BitAdr
}; //获取FINS通信结果
finsResult = await PLC.Write_MemoryAreaAsync(IOMemoryAreaAdr, finsFrameConfig, WriteCount, WriteData); if (finsResult.IsSuccessed)
{
return finsResult.ResultMessage;
}
else
{
throw new Exception($"{finsResult.ResultMessage}{Environment.NewLine}{Environment.NewLine}发送命令帧:{finsResult.CommandFrame}{Environment.NewLine}接收回复帧:{finsResult.ResponseFrame}");
}
}
catch (Exception)
{
throw;
}
}
}

Program.cs

internal class Program
{
static async Task Main(string[] args)
{
#region C-Mode方式 HostLinkCmodeDevice plc1 = new HostLinkCmodeDevice("COM5", 115200, Parity.None, 8, StopBits.One); SemaphoreSlim semaphoreSlim_Comm1 = new SemaphoreSlim(1, 1); plc1.Connect(); var Task1 = Task.Run(async () =>
{
await semaphoreSlim_Comm1.WaitAsync(); Stopwatch stopwatch1 = new Stopwatch(); stopwatch1.Start(); string str1 = await plc1.TestCommandAsync("123123"); stopwatch1.Stop(); Console.WriteLine("TestCommand:"); Console.WriteLine(str1); Console.WriteLine($"花费时间:{stopwatch1.ElapsedMilliseconds}ms"); semaphoreSlim_Comm1.Release(); }); var Task2 = Task.Run(async () =>
{
await semaphoreSlim_Comm1.WaitAsync(); Stopwatch stopwatch1 = new Stopwatch(); stopwatch1.Start(); string str1 = await plc1.Read_DMAreaAsync(0, 3); stopwatch1.Stop(); Console.WriteLine("ReadDM:"); Console.WriteLine(str1); Console.WriteLine($"花费时间:{stopwatch1.ElapsedMilliseconds}ms"); semaphoreSlim_Comm1.Release(); }); await Task.WhenAll(Task1, Task2); plc1.DisConnect(); semaphoreSlim_Comm1.Dispose(); #endregion #region FINS-Mode方式 //HostLinkDevice plc2 = new HostLinkDevice("COM5", 115200, Parity.None, 8, StopBits.One); //SemaphoreSlim semaphoreSlim_Comm2 = new SemaphoreSlim(1, 1); //plc2.Connect(); //var Task3 = Task.Run(async () =>
//{
// await semaphoreSlim_Comm2.WaitAsync(); // Stopwatch stopwatch2 = new Stopwatch(); // stopwatch2.Start(); // var list1 = await plc2.ReadCIOBitAsync(100, 0, 3); // stopwatch2.Stop(); // Console.WriteLine("Read CIOBit:");
// foreach (var item in list1)
// {
// Console.WriteLine(item);
// } // Console.WriteLine($"花费时间:{stopwatch2.ElapsedMilliseconds}ms"); // semaphoreSlim_Comm2.Release();
//}); //var Task4 = Task.Run(async () =>
//{
// await semaphoreSlim_Comm2.WaitAsync(); // Stopwatch stopwatch2 = new Stopwatch(); // stopwatch2.Start(); // var list1 = await plc2.ReadWRBitAsync(0, 0, 3); // stopwatch2.Stop(); // Console.WriteLine("Read WRBit:");
// foreach (var item in list1)
// {
// Console.WriteLine(item);
// } // Console.WriteLine($"花费时间:{stopwatch2.ElapsedMilliseconds}ms"); // semaphoreSlim_Comm2.Release();
//}); //var Task5 = Task.Run(async () =>
//{
// await semaphoreSlim_Comm2.WaitAsync(); // Stopwatch stopwatch2 = new Stopwatch(); // stopwatch2.Start(); // var list1 = await plc2.WriteWRBitAsync(0, 0, 3, "000100"); // stopwatch2.Stop(); // Console.WriteLine("Write WRBit:");
// Console.WriteLine(list1); // Console.WriteLine($"花费时间:{stopwatch2.ElapsedMilliseconds}ms"); // semaphoreSlim_Comm2.Release();
//}); //await Task.WhenAll(Task3, Task4, Task5); //plc2.Disconnect();
//semaphoreSlim_Comm2.Dispose(); #endregion Console.ReadKey();
}
}

具体项目请自行到控制台测试项目Gitee 仓库查看吧

测试结果

控制台输出图如下:

C-Mode方式

FINS-Mode方式

C#实现欧姆龙 HostLink 通讯协议库的更多相关文章

  1. 欧姆龙plc通讯协议格式

    欧姆龙CPM1A型plc与上位计算机通信的顺序是上位机先发出命令信息给PLC,PLC返回响应信息给上位 机.每次通信发送/接受的一组数据称为一"帧".帧由少于131个字符的数据构成 ...

  2. 【转】常用PLC通讯协议

    三菱FX系列PLC通讯测试 发送帧(Hex): 起始(STX) 02 命令(CMD) 30 首地址(ADDRESS) 30 30 41 30 字节数(BYTES) 30 31 终止(ETX) 03 校 ...

  3. HslCommunication库的二次协议扩展,适配第三方通讯协议开发,基础框架支持长短连接模式

    本文将使用一个gitHub开源的项目来扩展实现二次协议的开发,该项目已经搭建好了基础层架构,并实现了三菱,西门子,欧姆龙,MODBUS-TCP的通讯示例,也可以参照这些示例开发其他的通讯协议,并Pul ...

  4. 使用delphi 开发多层应用(十六)使用XMLRPC 实现basic4android 远程调用RTC服务(讲述了RTC的特点,其底层通讯协议是自己封装SOCK 库,与kbmmw 的适合场合不完全一样)

        RealThinClient (以下简称RTC) 也是一款delphi 多层开发的框架,由于其底层通讯协议是自己封装SOCK 库,抛弃了 大家诟病的indy,因此表现的非常稳定,效率也非常高, ...

  5. 2018-2019-1-20165221&20165225 《信息安全系统设计》实验五:通讯协议设计

    2018-2019-1-20165221&20165225 <信息安全系统设计>-实验五:通讯协议设计 OpenSSL学习: 简介: OpenSSL是为网络通信提供安全及数据完整性 ...

  6. Mavlink - 无人机通讯协议

    http://qgroundcontrol.org/mavlink/start mavlink协议介绍https://pixhawk.ethz.ch/mavlink/ 消息简介 MAVLink简介 M ...

  7. MQTT是IBM开发的一个即时通讯协议,构建于TCP/IP协议上,是物联网IoT的订阅协议,借助消息推送功能,可以更好地实现远程控制

    最近一直做物联网方面的开发,以下内容关于使用MQTT过程中遇到问题的记录以及需要掌握的机制原理,主要讲解理论. 背景 MQTT是IBM开发的一个即时通讯协议.MQTT构建于TCP/IP协议上,面向M2 ...

  8. 基于dubbo框架下的RPC通讯协议性能测试

    一.前言 Dubbo RPC服务框架支持丰富的传输协议.序列化方式等通讯相关的配置和扩展.dubbo执行一次RPC请求的过程大致如下:消费者(Consumer)向注册中心(Registry)执行RPC ...

  9. MODBUS-RTU通讯协议简介

    MODBUS-RTU通讯协议简介   什么是MODBUS? MODBUS 是MODICON公司最先倡导的一种软的通讯规约,经过大多数公司 的实际应用,逐渐被认可,成为一种标准的通讯规约,只要按照这种规 ...

  10. 【读书笔记】iOS-防止通讯协议被轻易破解的方法

    开发者可以选择类似Protobuf之类的二进制通讯协议或者自己实现通讯协议,对于传输的内容进行一定程度的加密,以增加黑客破解协议的难度. 参考资料: <iOS开发进阶> --唐巧

随机推荐

  1. Failed to start MySQL 8.0 database server.

    原因 在mysql错误日志里出现:The innodb_system data file 'ibdata1' must be writable,字面意思:ibdata1必须可写 查看日志报错,文件夹无 ...

  2. linux curl 测试 websocket 服务

    如下 curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" -H "Host: ec ...

  3. 如何每5分钟、10分钟或15分钟运行一次Cron计划任务

    一个cron job是一个在指定时间段执行的任务.这些任务可以按分钟.小时.月.日.周.日或这些的任何组合来安排运行. Cron作业一般用于自动化系统维护或管理,例如备份数据库或数据.用最新的安全补丁 ...

  4. 视觉SLAM十四讲——有关相机运动的汇报

    视觉SLAM十四讲--有关相机运动的汇报 大概用了一个月的时间看完slam十四讲,里面很多内容算是填坑了很多以前遇到的不懂的点,并且脑海里也大致有了一个关于SLAM的框架,现在就这篇文章将其中相机运动 ...

  5. nacos(八): sentinel——基本使用

    一.概要 在微服务的架构中,流控是一个重要的任务.sentinel是阿里开源的流量治理组件,针对访问的"资源"或服务路径进行流控,内置了限流.熔断及系统负载保护等功能. senti ...

  6. cURL 工具库基本使用

    cURL(Client URL)是一个功能强大的工具和库,用于与各种网络协议进行交互,cURL常用的一些参数和示例代码: -X, --request :指定HTTP请求方法(GET.POST.PUT等 ...

  7. 🎀chrome-截图录屏插件-Awesome Screenshot

    简介 Awesome Screenshot 截图录屏是一款浏览器扩展程序,它可以帮助用户进行网页截图.编辑图片以及录制屏幕视频 版本 4.4.22 功能 截图:可以截取整个网页(即使是需要滚动才能看到 ...

  8. Linux之用户和用户组管理

    概念 Linux系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须要拥有一个账号进入系统,账号实质上就是一个用户在系统上的标识.系统根据标识分配不同的权限和资源.一个账号包含用 ...

  9. pytorch 实战教程之 SPP(SPPNet---Spatial Pyramid Pooling)空间金字塔池化网络代码实现 和 SPPF (Spatial Pyramid Pooling Fast)详解​​

    原文作者:aircraft 原文链接:pytorch 实战教程之 SPP(SPPNet---Spatial Pyramid Pooling)空间金字塔池化网络代码实现 和 SPPF (Spatial ...

  10. Java 中的强引用、软引用、弱引用和虚引用分别是什么?

    Java 中的引用类型:强引用.软引用.弱引用和虚引用 Java 中的引用类型主要分为 强引用.软引用.弱引用 和 虚引用,它们对对象的生命周期和垃圾回收(GC)行为产生不同的影响. 1. 强引用(S ...