-
-
Notifications
You must be signed in to change notification settings - Fork 363
feat(ITcpSocketFactory): add ITcpSocketFactory service #6254
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 35 commits
Commits
Show all changes
38 commits
Select commit
Hold shift + click to select a range
c7f2dff
feat: 增加扩展方法判断当前环境是否为 IsWasm
ArgoZhang c777b6f
feat: 增加 ITcpSocketFactory 服务
ArgoZhang 130949e
refactor: 更新 ConnectAsync 接口
ArgoZhang c23703d
test: 更新单元测试
ArgoZhang c0d1ac5
refactor: 增加 ITcpSocketClient 服务
ArgoZhang 2ce01c1
test: 增加单元测试
ArgoZhang f5f0ba1
refactor: 重构日志实例逻辑
ArgoZhang 95ccd15
refactor: 精简代码
ArgoZhang 8898e7a
refactor: 增加取消记录日志逻辑
ArgoZhang 455b445
refactor: 增加 Close 方法
ArgoZhang 283caaa
test: 增加实例单元测试
ArgoZhang 033b0c2
feat: 增加 IDataPackageAdapter 接口
ArgoZhang 60c122e
refactor: 增加设置本地节点逻辑
ArgoZhang 86217e1
refactor: 增加数据处理器功能
ArgoZhang 415c588
refactor: 增加 virtual 关键字
ArgoZhang 2ef702d
test: 增加单元测试
ArgoZhang 3162a01
test: 更新单元测试
ArgoZhang fda1c32
feat: 增加数据处理类
ArgoZhang 2d087f6
refactor: 增加连接后自动接收逻辑
ArgoZhang 0474f66
test: 增加单元测试
ArgoZhang 8802cdf
refactor: 增加接收任务取消逻辑
ArgoZhang cf5fa85
refactor: 精简代码逻辑
ArgoZhang f20cf3e
test: 更新单元测试
ArgoZhang db7d408
refactor: 实现拆包粘包处理逻辑
ArgoZhang c498fea
refactor: 优化代码 Logger 不为空
ArgoZhang 056147d
test: 更新单元测试
ArgoZhang 9567cf9
test: 增加 SendAsync 单元测试
ArgoZhang a772e36
test: 增加 Factory 单元测试
ArgoZhang 2b23292
test: 精简单元测试
ArgoZhang 8b588e8
Merge branch 'main' into feat-socket
ArgoZhang a9eb67f
test: 增加 IsWasm 单元测试
ArgoZhang 44e4bd3
refactor: 接收方法内异常改为日志
ArgoZhang efdd447
refactor: 防止缓存区被释放
ArgoZhang e4d04f7
refactor: 精简代码提高可读性
ArgoZhang b6e0e6f
Revert "refactor: 接收方法内异常改为日志"
ArgoZhang fc13b5f
refactor: 更正方法名称为 HandleStickyPackage
ArgoZhang 6ea1b25
refactor: 更改申请缓存区代码
ArgoZhang ef65e62
refactor: 重构拆包方法名称
ArgoZhang File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
21 changes: 21 additions & 0 deletions
21
src/BootstrapBlazor/Extensions/HostEnvironmentExtensions.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the Apache 2.0 License | ||
| // See the LICENSE file in the project root for more information. | ||
| // Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone | ||
|
|
||
| using Microsoft.Extensions.Hosting; | ||
|
|
||
| namespace BootstrapBlazor.Components; | ||
|
|
||
| /// <summary> | ||
| /// <see cref="IHostEnvironment"/> 扩展方法" | ||
| /// </summary> | ||
| public static class HostEnvironmentExtensions | ||
| { | ||
| /// <summary> | ||
| /// 当前程序是否为 WebAssembly 环境 | ||
| /// </summary> | ||
| /// <param name="hostEnvironment"></param> | ||
| /// <returns></returns> | ||
| public static bool IsWasm(this IHostEnvironment hostEnvironment) => hostEnvironment is MockWasmHostEnvironment; | ||
| } |
89 changes: 89 additions & 0 deletions
89
src/BootstrapBlazor/Services/TcpSocket/DataPackage/DataPackageHandlerBase.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the Apache 2.0 License | ||
| // See the LICENSE file in the project root for more information. | ||
| // Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone | ||
|
|
||
| namespace BootstrapBlazor.Components; | ||
|
|
||
| /// <summary> | ||
| /// Provides a base implementation for handling data packages in a communication system. | ||
| /// </summary> | ||
| /// <remarks>This abstract class defines the core contract for receiving and sending data packages. Derived | ||
| /// classes should override and extend its functionality to implement specific data handling logic. The default | ||
| /// implementation simply returns the provided data.</remarks> | ||
| public abstract class DataPackageHandlerBase : IDataPackageHandler | ||
| { | ||
| private Memory<byte> _lastReceiveBuffer = Memory<byte>.Empty; | ||
ArgoZhang marked this conversation as resolved.
Show resolved
Hide resolved
ArgoZhang marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| /// <summary> | ||
| /// 当接收数据处理完成后,回调该函数执行接收 | ||
| /// </summary> | ||
| public Func<Memory<byte>, Task>? ReceivedCallBack { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Sends the specified data asynchronously to the target destination. | ||
| /// </summary> | ||
| /// <remarks>The method performs an asynchronous operation to send the provided data. The caller must | ||
| /// ensure that the data is valid and non-empty. The returned memory block may contain a response or acknowledgment | ||
| /// depending on the implementation of the target destination.</remarks> | ||
| /// <param name="data">The data to be sent, represented as a block of memory.</param> | ||
| /// <returns>A task that represents the asynchronous operation. The task result contains a <see cref="Memory{T}"/> of <see | ||
| /// cref="byte"/> representing the response or acknowledgment received from the target destination.</returns> | ||
| public virtual Task<Memory<byte>> SendAsync(Memory<byte> data) | ||
| { | ||
| return Task.FromResult(data); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Processes the received data asynchronously. | ||
| /// </summary> | ||
| /// <param name="data">A memory buffer containing the data to be processed. The buffer must not be empty.</param> | ||
| /// <returns>A task that represents the asynchronous operation.</returns> | ||
| public virtual Task ReceiveAsync(Memory<byte> data) | ||
| { | ||
| return Task.CompletedTask; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Handles the processing of a sticky package by adjusting the provided buffer and length. | ||
| /// </summary> | ||
| /// <remarks>This method processes the portion of the buffer beyond the specified length and updates the | ||
| /// internal state accordingly. The caller must ensure that the <paramref name="buffer"/> contains sufficient data | ||
| /// for the specified <paramref name="length"/>.</remarks> | ||
| /// <param name="buffer">The memory buffer containing the data to process.</param> | ||
| /// <param name="length">The length of the valid data within the buffer.</param> | ||
| protected void HandlerStickyPackage(Memory<byte> buffer, int length) | ||
ArgoZhang marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
ArgoZhang marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| { | ||
| if (buffer.Length > length) | ||
| { | ||
| _lastReceiveBuffer = buffer[length..].ToArray().AsMemory(); | ||
| } | ||
| } | ||
ArgoZhang marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| /// <summary> | ||
| /// Concatenates the provided buffer with any previously stored data and returns the combined result. | ||
| /// </summary> | ||
| /// <remarks>This method combines the provided buffer with any data stored in the internal buffer. After | ||
| /// concatenation, the internal buffer is cleared. The returned memory block is allocated from a shared memory pool | ||
| /// and should be used promptly to avoid holding onto pooled resources.</remarks> | ||
| /// <param name="buffer">The buffer to concatenate with the previously stored data. Must not be empty.</param> | ||
| /// <returns>A <see cref="Memory{T}"/> instance containing the concatenated data. If no previously stored data exists, the | ||
| /// method returns the input <paramref name="buffer"/>.</returns> | ||
| protected Memory<byte> ConcatBuffer(Memory<byte> buffer) | ||
ArgoZhang marked this conversation as resolved.
Show resolved
Hide resolved
ArgoZhang marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| { | ||
| if (_lastReceiveBuffer.IsEmpty) | ||
| { | ||
| return buffer; | ||
| } | ||
|
|
||
| // 计算缓存区长度 | ||
| var total = _lastReceiveBuffer.Length + buffer.Length; | ||
| var merged = new byte[total]; | ||
ArgoZhang marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| _lastReceiveBuffer.CopyTo(merged); | ||
| buffer.CopyTo(merged.AsMemory(_lastReceiveBuffer.Length)); | ||
|
|
||
| // Clear the sticky buffer | ||
| _lastReceiveBuffer = Memory<byte>.Empty; | ||
| return merged; | ||
ArgoZhang marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| } | ||
55 changes: 55 additions & 0 deletions
55
src/BootstrapBlazor/Services/TcpSocket/DataPackage/FixLengthDataPackageHandler.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the Apache 2.0 License | ||
| // See the LICENSE file in the project root for more information. | ||
| // Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone | ||
|
|
||
| namespace BootstrapBlazor.Components; | ||
|
|
||
| /// <summary> | ||
| /// Handles fixed-length data packages by processing incoming data of a specified length. | ||
| /// </summary> | ||
| /// <remarks>This class is designed to handle data packages with a fixed length, as specified during | ||
| /// initialization. It extends <see cref="DataPackageHandlerBase"/> and overrides its behavior to process fixed-length | ||
| /// data.</remarks> | ||
| /// <param name="length">The data package total data length.</param> | ||
| public class FixLengthDataPackageHandler(int length) : DataPackageHandlerBase | ||
ArgoZhang marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| { | ||
| private readonly Memory<byte> _data = new byte[length]; | ||
ArgoZhang marked this conversation as resolved.
Show resolved
Hide resolved
ArgoZhang marked this conversation as resolved.
Show resolved
Hide resolved
ArgoZhang marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| private int _receivedLength; | ||
|
|
||
| /// <summary> | ||
| /// <inheritdoc/> | ||
| /// </summary> | ||
| /// <param name="data"></param> | ||
| /// <returns></returns> | ||
| public override async Task ReceiveAsync(Memory<byte> data) | ||
ArgoZhang marked this conversation as resolved.
Show resolved
Hide resolved
ArgoZhang marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| { | ||
| // 处理上次粘包数据 | ||
| data = ConcatBuffer(data); | ||
|
|
||
| // 拷贝数据 | ||
| var len = length - _receivedLength; | ||
| var segment = data.Length > len ? data[..len] : data; | ||
| segment.CopyTo(_data[_receivedLength..]); | ||
|
|
||
| if(data.Length > len) | ||
ArgoZhang marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
ArgoZhang marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
ArgoZhang marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| { | ||
| HandlerStickyPackage(data, data.Length - len); | ||
| } | ||
|
|
||
| // 更新已接收长度 | ||
| _receivedLength += segment.Length; | ||
|
|
||
| // 如果已接收长度等于总长度则触发回调 | ||
| if (_receivedLength == length) | ||
ArgoZhang marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| { | ||
| // 重置已接收长度 | ||
| _receivedLength = 0; | ||
| if (ReceivedCallBack != null) | ||
| { | ||
| await ReceivedCallBack(_data); | ||
| } | ||
| } | ||
| } | ||
| } | ||
41 changes: 41 additions & 0 deletions
41
src/BootstrapBlazor/Services/TcpSocket/DataPackage/IDataPackageHandler.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the Apache 2.0 License | ||
| // See the LICENSE file in the project root for more information. | ||
| // Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone | ||
|
|
||
| namespace BootstrapBlazor.Components; | ||
|
|
||
| /// <summary> | ||
| /// Defines an interface for adapting data packages to and from a TCP socket connection. | ||
| /// </summary> | ||
| /// <remarks>Implementations of this interface are responsible for converting raw data received from a TCP socket | ||
| /// into structured data packages and vice versa. This allows for custom serialization and deserialization logic | ||
| /// tailored to specific application protocols.</remarks> | ||
| public interface IDataPackageHandler | ||
| { | ||
| /// <summary> | ||
| /// Gets or sets the callback function to be invoked when data is received asynchronously. | ||
| /// </summary> | ||
| Func<Memory<byte>, Task>? ReceivedCallBack { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Sends the specified data asynchronously to the target destination. | ||
| /// </summary> | ||
| /// <remarks>The method performs an asynchronous operation to send the provided data. The caller must | ||
| /// ensure that the data is valid and non-empty. The returned memory block may contain a response or acknowledgment | ||
| /// depending on the implementation of the target destination.</remarks> | ||
| /// <param name="data">The data to be sent, represented as a block of memory.</param> | ||
| /// <returns>A task that represents the asynchronous operation. The task result contains a <see cref="Memory{T}"/> of <see | ||
| /// cref="byte"/> representing the response or acknowledgment received from the target destination.</returns> | ||
| Task<Memory<byte>> SendAsync(Memory<byte> data); | ||
|
|
||
| /// <summary> | ||
| /// Asynchronously receives data from a source and writes it into the provided memory buffer. | ||
| /// </summary> | ||
| /// <remarks>This method does not guarantee that the entire buffer will be filled. The number of bytes | ||
| /// written depends on the availability of data.</remarks> | ||
| /// <param name="data">The memory buffer to store the received data. The buffer must be writable and have sufficient capacity.</param> | ||
| /// <returns>A task that represents the asynchronous operation. The task result contains the number of bytes written to the | ||
| /// buffer. Returns 0 if the end of the data stream is reached.</returns> | ||
| Task ReceiveAsync(Memory<byte> data); | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.