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. 堆排序(标准版)(NB)

    博客地址:https://www.cnblogs.com/zylyehuo/ # _*_coding:utf-8_*_ import random def sift(li, low, high): # ...

  2. Redis 原理 - List

    List 数据结构 Redis 3.2 前,使用 压缩列表zipList 或 双向链表linkedList 当同时满足下面两个条件时,使用zipList存储数据 list保存的每个元素长度小于64字节 ...

  3. C# 13 中的新增功能实操

    前言 今天大姚带领大家一起来看看 C# 13 中的新增几大功能,并了解其功能特性和实际应用场景. 前提准备 要体验 C# 13 新增的功能可以使用最新的 Visual Studio 2022 版本或 ...

  4. 把postgreSQL的表导入SQLite

    万能的互联网,一查一大堆废话,几乎搞不定.现将查到的资料结合实践概况如下,对不对也不清楚,反正可以跑了. 1.把PostgreSQL的表SQL语句复制出来 CREATE TABLE "mai ...

  5. 阿里巴巴暑期实习 Java 面经,灵犀互娱一面

    哈希表熟悉吗,可以如何实现? 开散列版本什么时候需要扩容 高并发服务器内的主从reactor模型是如何实现的? 进程 线程 协程 的区别? 如何保证线程安全 ? 了解读写锁吗? 单例模式有了解吗? 可 ...

  6. Volatile:内存可见性

    一.当写一个volatile变量时,JMM会把该线程对应的本地中的共享变量值刷新到主内存. 例子: /* * 一.volatile 关键字:当多个线程进行操作共享数据时,可以保证内存中的数据可见. * ...

  7. windows10 激活教程

    1.环境 适用对象:VL版本的windows OEM版本请使用文末工具激活 1.1查询自己电脑版本 [win+R]->输入[slmgr /dlv]->查看[产品密钥通道] slmgr /d ...

  8. python实例:爬取caoliu图片,同时下载到指定的文件夹内

    本脚本主要实现爬取caoliu某图片板块,前3页当天更新的帖子的所有图片,同时把图片下载到对应帖子名创建的文件夹中 爬虫主要通过python xpath来实现,同时脚本内包含,创建文件夹,分割数据,下 ...

  9. MySQL 的索引类型有哪些?

    MySQL 的索引类型 MySQL 提供多种索引类型,用于优化数据查询性能.每种索引类型在存储结构.适用场景和性能特性方面各不相同. 1. 常见的索引类型 (1)B+树索引 结构:基于 B+ 树实现, ...

  10. git提示fatal: Authentication failed for但是不进入重新登录的流程,也死活不弹窗的解决办法,不用找证书删

    问题: git提交代码输错了密码,提示 fatal: Authentication failed for xxx 但是不进入重新登录的流程,也死活不弹窗. 感觉git的这个设计真的很沙雕.网上说删证书 ...