当前位置:网站首页>How can C TCP set heartbeat packets to be elegant?
How can C TCP set heartbeat packets to be elegant?
2022-07-05 16:55:00 【Ruo Qiming】
List of articles
One 、 explain
Why set the heartbeat ?
The heartbeat mechanism sends a customized message at regular intervals Structure ( Heartbeat bag ), Let the other person know that they are still alive , To ensure the validity of the connection . The data received and sent in the network are all from the operating system SOCKET To implement . But if this Socket It's disconnected , There must be problems when sending and receiving data . But how to judge whether this socket can still be used ? This requires creating a heartbeat mechanism in the system . Actually TCP A mechanism called heartbeat has been implemented for us in .
But this mechanism is limited by the operating system , And it's easy to make false positives . So it is rarely used by everyone .
The most used , Is to design the data package by yourself , Then reserve the heartbeat format , When the other party receives the heartbeat packet , Just return the response package directly .
that , In this way , Let's use RRQMSocket Elegant realization .
Two 、 Assembly source code
2.1 Source location
2.2 documentation
The front page of the document
3、 ... and 、 install
Nuget install RRQMSocket that will do , See link blog for specific steps .
VS、Unity Installation and use Nuget package
Four 、 data format
4.1 Design data format
Before using heartbeat , The data format must be clear , Never confuse business data . Generally, it fits Plc When waiting for ready-made modules , They have a fixed data format , At this time, you can refer to Data processing adapter , Quickly parse data .
But in this article , There is no prescribed format , So we need to design a simple and efficient data format first .
as follows :
| Data length | data type | Load data |
|---|---|---|
| 2 byte (Ushort) | 1 byte (Byte) | n byte (<65535) |
4.2 Parse data format
class MyFixedHeaderDataHandlingAdapter : CustomFixedHeaderDataHandlingAdapter<MyRequestInfo>
{
public override int HeaderLength => 3;
protected override MyRequestInfo GetInstance()
{
return new MyRequestInfo();
}
}
class MyRequestInfo : IFixedHeaderRequestInfo
{
public DataType DataType {
get; set; }
public byte[] Data {
get; set; }
public int BodyLength {
get; private set; }
public bool OnParsingBody(byte[] body)
{
if (body.Length == this.BodyLength)
{
this.Data = body;
return true;
}
return false;
}
public bool OnParsingHeader(byte[] header)
{
if (header.Length == 3)
{
this.BodyLength = RRQMBitConverter.Default.ToUInt16(header, 0)-1;
this.DataType = (DataType)header[2];
return true;
}
return false;
}
public void Package(ByteBlock byteBlock)
{
byteBlock.Write((ushort)((this.Data == null ? 0 : this.Data.Length) + 1));
byteBlock.Write((byte)this.DataType);
byteBlock.Write(Data);
}
public byte[] PackageAsBytes()
{
using ByteBlock byteBlock = new ByteBlock();
this.Package(byteBlock);
return byteBlock.ToArray();
}
public override string ToString()
{
return $" data type ={
this.DataType}, data ={
(this.Data==null?"null":Encoding.UTF8.GetString(this.Data))}";
}
}
enum DataType : byte
{
Ping,
Pong,
Data
}
5、 ... and 、 Create an extension class
/// <summary>
/// A heartbeat counter extension .
/// </summary>
static class DependencyExtensions
{
public static readonly DependencyProperty HeartbeatTimerProperty =
DependencyProperty.Register("HeartbeatTimer", typeof(Timer), typeof(DependencyExtensions), null);
public static bool Ping<TClient>(this TClient client)where TClient:ITcpClientBase
{
try
{
client.Send(new MyRequestInfo() {
DataType = DataType.Ping }.PackageAsBytes());
return true;
}
catch(Exception ex)
{
client.Logger.Exception(ex);
}
return false;
}
public static bool Pong<TClient>(this TClient client) where TClient : ITcpClientBase
{
try
{
client.Send(new MyRequestInfo() {
DataType = DataType.Pong }.PackageAsBytes());
return true;
}
catch (Exception ex)
{
client.Logger.Exception(ex);
}
return false;
}
}
6、 ... and 、 Create heartbeat plug-in class
class HeartbeatAndReceivePlugin : TcpPluginBase
{
private readonly int m_timeTick;
[DependencyInject(1000*5)]
public HeartbeatAndReceivePlugin(int timeTick)
{
this.m_timeTick = timeTick;
}
protected override void OnConnecting(ITcpClientBase client, ClientOperationEventArgs e)
{
client.SetDataHandlingAdapter(new MyFixedHeaderDataHandlingAdapter());// Setup adapter .
base.OnConnecting(client, e);
}
protected override void OnConnected(ITcpClientBase client, RRQMEventArgs e)
{
if (client is ISocketClient)
{
return;// It can be judged here , If it is a server , Do not use heartbeat .
}
if (client.GetValue<Timer>(DependencyExtensions.HeartbeatTimerProperty) is Timer timer)
{
timer.Dispose();
}
client.SetValue(DependencyExtensions.HeartbeatTimerProperty,new Timer((o)=>
{
client.Ping();
},null,0, m_timeTick));
base.OnConnected(client, e);
}
protected override void OnDisconnected(ITcpClientBase client, ClientDisconnectedEventArgs e)
{
base.OnDisconnected(client, e);
if (client.GetValue<Timer>(DependencyExtensions.HeartbeatTimerProperty) is Timer timer)
{
timer.Dispose();
client.SetValue(DependencyExtensions.HeartbeatTimerProperty,null);
}
}
protected override void OnReceivedData(ITcpClientBase client, ReceivedDataEventArgs e)
{
if (e.RequestInfo is MyRequestInfo myRequest)
{
client.Logger.Message(myRequest.ToString());
if (myRequest.DataType== DataType.Ping)
{
client.Pong();
}
}
base.OnReceivedData(client, e);
}
}
7、 ... and 、 test 、 start-up
class Program
{
static TcpService service = new TcpService();
static TcpClient tcpClient = new TcpClient();
static void Main(string[] args)
{
ConsoleAction consoleAction = new ConsoleAction();
service.Setup(new RRQMConfig()// Load configuration
.SetListenIPHosts(new IPHost[] {
new IPHost("127.0.0.1:7789"), new IPHost(7790) })// Listen to two addresses at the same time
.SetMaxCount(10000)
.UsePlugin()
.SetThreadCount(10))
.Start();// start-up
service.AddPlugin<HeartbeatAndReceivePlugin>();
service.Logger.Message(" Server started successfully ");
tcpClient.Setup(new RRQMConfig()
.SetRemoteIPHost(new IPHost("127.0.0.1:7789"))
.UsePlugin()
.SetBufferLength(1024 * 10));
tcpClient.AddPlugin<HeartbeatAndReceivePlugin>();
tcpClient.Connect();
tcpClient.Logger.Message(" Client successfully connected ");
consoleAction.OnException += ConsoleAction_OnException;
consoleAction.Add("1", " Send a heartbeat ", () =>
{
tcpClient.Ping();
});
consoleAction.Add("2", " send data ", () =>
{
tcpClient.Send(new MyRequestInfo()
{
DataType = DataType.Data,
Data = Encoding.UTF8.GetBytes(Console.ReadLine())
}
.PackageAsBytes());
});
consoleAction.ShowAll();
while (true)
{
consoleAction.Run(Console.ReadLine());
}
}
private static void ConsoleAction_OnException(Exception obj)
{
Console.WriteLine(obj);
}
}
8、 ... and 、 effect

this paper Example demo
边栏推荐
- Get ready for the pre-season card game MotoGP ignition champions!
- How to uninstall MySQL cleanly
- 机器学习编译第2讲:张量程序抽象
- [deep learning] [original] let yolov6-0.1.0 support the txt reading dataset mode of yolov5
- Jarvis OJ Webshell分析
- 国产芯片产业链两条路齐头并进,ASML真慌了而大举加大合作力度
- 【剑指 Offer】62. 圆圈中最后剩下的数字
- HiEngine:可媲美本地的云原生内存数据库引擎
- 【剑指 Offer】63. 股票的最大利润
- 阈值同态加密在隐私计算中的应用:解读
猜你喜欢
随机推荐
If you can't afford a real cat, you can use code to suck cats -unity particles to draw cats
Win11如何给应用换图标?Win11给应用换图标的方法
Flet教程之 11 Row组件在水平数组中显示其子项的控件 基础入门(教程含源码)
Summary of methods for finding intersection of ordered linked list sets
阈值同态加密在隐私计算中的应用:解读
机器学习编译第2讲:张量程序抽象
[js] 技巧 简化if 判空
【刷題篇】鹅廠文化衫問題
Cs231n notes (bottom) - applicable to 0 Foundation
Jarvis OJ Webshell分析
[brush questions] effective Sudoku
WSL2.0安装
Data access - entityframework integration
Deep learning plus
美国芯片傲不起来了,中国芯片成功在新兴领域夺得第一名
Explain in detail the functions and underlying implementation logic of the groups sets statement in SQL
怎样在电脑上设置路由器的WiFi密码
【剑指 Offer】62. 圆圈中最后剩下的数字
Combined use of vant popup+ other components and pit avoidance Guide
HiEngine:可媲美本地的云原生内存数据库引擎



![[brush title] goose factory shirt problem](/img/c8/44496c767a778101cf3982bd911933.png)




