当前位置:网站首页>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
边栏推荐
- 帮忙看看是什么问题可以吗?[ERROR] Could not execute SQL stateme
- 【刷題篇】鹅廠文化衫問題
- Google Earth engine (GEE) -- a brief introduction to kernel kernel functions and gray level co-occurrence matrix
- 【刷题篇】有效的数独
- [deep learning] [original] let yolov6-0.1.0 support the txt reading dataset mode of yolov5
- 【微信小程序】一文读懂小程序的生命周期和路由跳转
- China Radio and television officially launched 5g services, and China Mobile quickly launched free services to retain users
- Apple has abandoned navigationview and used navigationstack and navigationsplitview to implement swiftui navigation
- Games101 notes (III)
- Pspnet | semantic segmentation and scene analysis
猜你喜欢
![[brush questions] effective Sudoku](/img/5b/3064170bebd1ccbee68d6a85d23830.png)
[brush questions] effective Sudoku

Jarvis OJ shell traffic analysis

【学术相关】多位博士毕业去了三四流高校,目前惨不忍睹……

Flet教程之 12 Stack 重叠组建图文混合 基础入门(教程含源码)

浏览器渲染原理以及重排与重绘

If you can't afford a real cat, you can use code to suck cats -unity particles to draw cats

Starkware: to build ZK "universe"

Solve cmakelist find_ Package cannot find Qt5, ECM cannot be found

Jarvis OJ Telnet Protocol

Oneforall installation and use
随机推荐
[team PK competition] the task of this week has been opened | question answering challenge to consolidate the knowledge of commodity details
DenseNet
Flet教程之 12 Stack 重叠组建图文混合 基础入门(教程含源码)
【微信小程序】一文读懂小程序的生命周期和路由跳转
文件操作--I/O
微信公众号网页授权登录实现起来如此简单
[deep learning] [original] let yolov6-0.1.0 support the txt reading dataset mode of yolov5
Jarvis OJ Flag
[brush title] goose factory shirt problem
关于new Map( )还有哪些是你不知道的
Flet教程之 11 Row组件在水平数组中显示其子项的控件 基础入门(教程含源码)
手机开证券账户安全吗?怎么买股票详细步骤
How was the middle table destroyed?
Flet tutorial 12 stack overlapping to build a basic introduction to graphic and text mixing (tutorial includes source code)
StarkWare:欲构建ZK“宇宙”
composer安装报错:No composer.lock file present.
scratch五彩糖葫芦 电子学会图形化编程scratch等级考试三级真题和答案解析2022年6月
Timestamp strtotime the day before or after the date
Hiengine: comparable to the local cloud native memory database engine
How to install MySQL