Skip to content

Commit 4ce223e

Browse files
authored
feat(ITcpSocketClient): add ReceivedCallback property (#6266)
* feat: 增加 ReceivedCallBack 回调方法 * test: 增加单元测试 * doc: 更新示例文档
1 parent 31a2a95 commit 4ce223e

File tree

5 files changed

+46
-5
lines changed

5 files changed

+46
-5
lines changed

src/BootstrapBlazor.Server/Components/Samples/SocketFactories.razor

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ private ITcpSocketFactory? TcpSocketFactory { get; set; }</Pre>
2222
<li>通过 <code>ITcpSocketClient</code> 实例方法 <code>SendAsync</code> 发送协议数据</li>
2323
<li>通过 <code>ITcpSocketClient</code> 实例方法 <code>Close</code> 关闭连接</li>
2424
<li>通过 <code>ITcpSocketClient</code> 实例方法 <code>SetDataHandler</code> 方法设置数据处理器</li>
25+
<li>通过 <code>ITcpSocketClient</code> 实例属性 <code>ReceivedCallBack</code> 方法设置接收数据处理器(注意:此回调未做任何数据处理为原始数据)</li>
2526
</ul>
2627

2728
<p class="code-label">4. 数据处理器</p>
@@ -31,13 +32,13 @@ private ITcpSocketFactory? TcpSocketFactory { get; set; }</Pre>
3132
<p>数据处理器设计初衷就是为了契合通讯协议大大简化我们开发逻辑,我们已通讯协议每次通讯电文均为 <b>4</b> 位定长举例说明,在实际的通讯过程中,我们接收到的通讯数据存在粘包或者分包的现象</p>
3233

3334
<ul class="ul-demo">
34-
<li>粘包:比如我们期望收到 <b>1234</b> 四个字符,实际上我们接收到的是 <b>123412</b> 多出来的 <b>12</b> 其实是下一个通讯电文的内容,相邻两个通讯数据包的粘连称为粘包</li>
35-
<li>分包:比如我们期望收到 <b>1234</b> 四个字符,实际上我们接收到的是 <b>12</b> 和 <b>34</b> 两个数据包,这种情况称为分包</li>
35+
<li><b>粘包</b>:比如我们期望收到 <b>1234</b> 四个字符,实际上我们接收到的是 <b>123412</b> 多出来的 <b>12</b> 其实是下一个通讯电文的内容,相邻两个通讯数据包的粘连称为<b>粘包</b></li>
36+
<li><b>分包</b>:比如我们期望收到 <b>1234</b> 四个字符,实际上我们接收到的是 <b>12</b> 和 <b>34</b> 两个数据包,这种情况称为<b>分包</b></li>
3637
</ul>
3738

38-
<p>我们内置了 <code>IDataPackageHandler</code> 数据包处理接口,已经虚类 <code>DataPackageHandlerBase</code> 作为数据处理器基类已经内置了 <b>粘包</b> <b>分包</b> 的逻辑,继承此类后专注自己处理的业务即可</p>
39+
<p>我们内置了一些常用的数据处理类 <code>IDataPackageHandler</code> 接口为数据包处理接口,虚类 <code>DataPackageHandlerBase</code> 作为数据处理器基类已经内置了 <b>粘包</b> <b>分包</b> 的逻辑,继承此类后专注自己处理的业务即可</p>
3940

40-
<p>此外我们还内置了 <code>FixLengthDataPackageHandler</code> <b>固定长度数据处理器</b> 使用方法如下:</p>
41+
<p>使用方法如下:</p>
4142

4243
<Pre>[Inject]
4344
[NotNull]
@@ -64,3 +65,10 @@ private async Task CreateClient()
6465
var connected = await client.ConnectAsync("192.168.10.100", 6688);
6566
}
6667
</Pre>
68+
69+
<p>内置数据库处理器</p>
70+
71+
<ul class="ul-demo">
72+
<li><code>FixLengthDataPackageHandler</code> <b>固定长度数据处理器</b> 即每个通讯包都是固定长度</li>
73+
<li><code>DelimiterDataPackageHandler</code> <b>分隔符数据处理器</b> 即通讯包以特定一个或一组字节分割</li>
74+
</ul>

src/BootstrapBlazor/Services/TcpSocket/DataPackage/DataPackageHandlerBase.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@ public abstract class DataPackageHandlerBase : IDataPackageHandler
1616
private Memory<byte> _lastReceiveBuffer = Memory<byte>.Empty;
1717

1818
/// <summary>
19-
/// 当接收数据处理完成后,回调该函数执行接收
19+
/// Gets or sets the callback function to handle received data.
2020
/// </summary>
21+
/// <remarks>The callback function should be designed to handle the received data efficiently and
22+
/// asynchronously. Ensure that the implementation does not block or perform long-running operations, as this may
23+
/// impact performance.</remarks>
2124
public Func<ReadOnlyMemory<byte>, ValueTask>? ReceivedCallBack { get; set; }
2225

2326
/// <summary>

src/BootstrapBlazor/Services/TcpSocket/DefaultTcpSocketClient.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ class DefaultTcpSocketClient : ITcpSocketClient
2828

2929
public int ReceiveBufferSize { get; set; } = 1024 * 10;
3030

31+
public Func<ReadOnlyMemory<byte>, ValueTask>? ReceivedCallBack { get; set; }
32+
3133
public DefaultTcpSocketClient(string host, int port = 0)
3234
{
3335
LocalEndPoint = new IPEndPoint(GetIPAddress(host), port);
@@ -136,6 +138,11 @@ private async ValueTask ReceiveAsync()
136138
{
137139
buffer = buffer[..len];
138140

141+
if (ReceivedCallBack != null)
142+
{
143+
await ReceivedCallBack(buffer);
144+
}
145+
139146
if (_dataPackageHandler != null)
140147
{
141148
await _dataPackageHandler.ReceiveAsync(buffer);

src/BootstrapBlazor/Services/TcpSocket/ITcpSocketClient.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ public interface ITcpSocketClient : IDisposable
3030
/// specific local endpoint, this property may return <see langword="null"/>.</remarks>
3131
IPEndPoint LocalEndPoint { get; }
3232

33+
/// <summary>
34+
/// Gets or sets the callback function to handle received data.
35+
/// </summary>
36+
/// <remarks>The callback function should be designed to handle the received data efficiently and
37+
/// asynchronously. Ensure that the implementation does not block or perform long-running operations, as this may
38+
/// impact performance.</remarks>
39+
Func<ReadOnlyMemory<byte>, ValueTask>? ReceivedCallBack { get; set; }
40+
3341
/// <summary>
3442
/// Configures the data handler to process incoming data packages.
3543
/// </summary>

test/UnitTest/Services/TcpSocketFactoryTest.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,12 +143,27 @@ public async Task ReceiveAsync_Error()
143143
Assert.Equal(1024 * 20, client.ReceiveBufferSize);
144144

145145
client.SetDataHandler(new MockReceiveErrorHandler());
146+
147+
ReadOnlyMemory<byte> buffer = ReadOnlyMemory<byte>.Empty;
148+
var tcs = new TaskCompletionSource();
149+
150+
// 增加接收回调方法
151+
client.ReceivedCallBack = b =>
152+
{
153+
buffer = b;
154+
tcs.SetResult();
155+
return ValueTask.CompletedTask;
156+
};
157+
146158
await client.ConnectAsync("localhost", port);
147159

148160
// 发送数据导致接收数据异常
149161
var data = new ReadOnlyMemory<byte>([1, 2, 3, 4, 5]);
150162
await client.SendAsync(data);
151163

164+
await tcs.Task;
165+
Assert.Equal(buffer.ToArray(), [1, 2, 3, 4, 5]);
166+
152167
// 关闭连接
153168
StopTcpServer(server);
154169
}

0 commit comments

Comments
 (0)