Skip to content

Commit

Permalink
Add more TcpClientConfig options
Browse files Browse the repository at this point in the history
  • Loading branch information
tinohager committed Nov 7, 2024
1 parent 9b126e0 commit ecfc69b
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 25 deletions.
19 changes: 14 additions & 5 deletions src/Nager.TcpClient.UnitTest/ConcurrentSendReceiveTcpClientTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,22 +50,31 @@ public async Task SendAndReceiveData_Successful()
var port = 4242;

var isDataReceived = false;
using var cancellationTokenSource = new CancellationTokenSource();

var testChars = new char[] { 'A', 'b', 'C', 'D', 'E', '0', '1', 'X', 'Y', 'z' };
var testDataLength = 2000;
var testDataLength = 1000;
var dataFragementCount = 3;
var receiveBuffer = new List<byte>();

var expectedReceiveDataLength = (testDataLength + 1) * testChars.Length; // 1 = newline character

var clientConfig = new TcpClientConfig
{
ReceiveBufferSize = testDataLength / 7
ReceiveBufferSize = testDataLength / dataFragementCount
};

void OnDataReceived(byte[] receivedData)
{
receiveBuffer.AddRange(receivedData);

isDataReceived = true;
Trace.WriteLine($"ReceivedData: {BitConverter.ToString(receivedData)}");
Trace.WriteLine($"{DateTime.Now:HH:mm:ss.fff} - ReceivedData: {BitConverter.ToString(receivedData)}");

if (receiveBuffer.Count >= expectedReceiveDataLength)
{
cancellationTokenSource.Cancel();
}
}

var mockLoggerTcpClient = LoggerHelper.GetLogger<TcpClient>();
Expand All @@ -75,7 +84,7 @@ void OnDataReceived(byte[] receivedData)
tcpClient.Connect(ipAddress, port, 1000);

var tasks = new List<Task>();
var barrier = new Barrier(testChars.Length);
using var barrier = new Barrier(testChars.Length);

for (var i = 0; i < testChars.Length; i++)
{
Expand All @@ -96,7 +105,7 @@ void OnDataReceived(byte[] receivedData)
await Task.WhenAll(tasks);

//Wait for response of echo server
await Task.Delay(1000);
await Task.Delay(15000, cancellationTokenSource.Token).ContinueWith(task => { });

tcpClient.Disconnect();
tcpClient.DataReceived -= OnDataReceived;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net6.0;net8.0;netcoreapp3.1</TargetFrameworks>
<TargetFrameworks>net6;net8</TargetFrameworks>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
Expand Down
7 changes: 6 additions & 1 deletion src/Nager.TcpClient.UnitTest/SendReceiveTcpClientTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,11 @@ public async Task SendAndReceiveDataWithSmallReceiveBuffer_Successful()
var data = Encoding.UTF8.GetBytes("ping\n");
var receiveBuffer = new List<byte>();

var dataPackagesReceived = 0;
void OnDataReceived(byte[] receivedData)
{
receiveBuffer.AddRange(receivedData);
dataPackagesReceived++;
}

var mockLoggerTcpClient = LoggerHelper.GetLogger<TcpClient>();
Expand All @@ -72,12 +74,15 @@ void OnDataReceived(byte[] receivedData)
tcpClient.DataReceived += OnDataReceived;
tcpClient.Connect(ipAddress, port, 1000);
await tcpClient.SendAsync(data);
await Task.Delay(400);
await Task.Delay(2000);
tcpClient.Disconnect();
tcpClient.DataReceived -= OnDataReceived;

var expectedDataPackages = (int)Math.Ceiling((double)data.Length / config.ReceiveBufferSize);
var isReceivedDataValid = Enumerable.SequenceEqual(receiveBuffer, data);

Assert.IsTrue(isReceivedDataValid, "Invalid data received");
Assert.AreEqual(expectedDataPackages, dataPackagesReceived);
}

[TestMethod]
Expand Down
2 changes: 1 addition & 1 deletion src/Nager.TcpClient/Nager.TcpClient.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

<TargetFrameworks>netstandard2.0;netstandard2.1;net6;net8</TargetFrameworks>

<Version>1.2.0</Version>
<Version>1.3.0</Version>
</PropertyGroup>

<ItemGroup>
Expand Down
40 changes: 25 additions & 15 deletions src/Nager.TcpClient/TcpClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ namespace Nager.TcpClient
public class TcpClient : IDisposable
{
private readonly ILogger<TcpClient> _logger;
private readonly TcpClientConfig _tcpClientConfig;

private readonly CancellationTokenSource _cancellationTokenSource;
private readonly CancellationTokenRegistration _streamCancellationTokenRegistration;
private readonly Task _dataReceiverTask;
Expand Down Expand Up @@ -67,13 +69,9 @@ public TcpClient(
clientConfig = new TcpClientConfig();
}

this._tcpClientConfig = clientConfig;
this._receiveBuffer = new byte[clientConfig.ReceiveBufferSize];

if (logger == default)
{
logger = new NullLogger<TcpClient>();
}
this._logger = logger;
this._logger = logger ?? new NullLogger<TcpClient>();

this._streamCancellationTokenRegistration = this._cancellationTokenSource.Token.Register(() =>
{
Expand Down Expand Up @@ -222,6 +220,18 @@ private bool SwitchToDisconnected()
}
}

private System.Net.Sockets.TcpClient CreateTcpClient()
{
return new System.Net.Sockets.TcpClient
{
ReceiveBufferSize = this._tcpClientConfig.ReceiveBufferSize,
ReceiveTimeout = this._tcpClientConfig.ReceiveTimeout,
SendBufferSize = this._tcpClientConfig.SendBufferSize,
SendTimeout = this._tcpClientConfig.SendTimeout,
NoDelay = this._tcpClientConfig.NoDelay
};
}

/// <summary>
/// Connect
/// </summary>
Expand Down Expand Up @@ -256,7 +266,7 @@ public bool Connect(

try
{
this._tcpClient = new System.Net.Sockets.TcpClient();
this._tcpClient = this.CreateTcpClient();

this._logger.LogDebug($"{nameof(Connect)} - Connecting");
IAsyncResult asyncResult = this._tcpClient.BeginConnect(ipAddressOrHostname, port, null, null);
Expand Down Expand Up @@ -324,7 +334,7 @@ public async Task<bool> ConnectAsync(
return false;
}

this._tcpClient = new System.Net.Sockets.TcpClient();
this._tcpClient = this.CreateTcpClient();

this._logger.LogDebug($"{nameof(ConnectAsync)} - Connecting");

Expand Down Expand Up @@ -368,7 +378,7 @@ public async Task<bool> ConnectAsync(
return false;
}

this._tcpClient = new System.Net.Sockets.TcpClient();
this._tcpClient = this.CreateTcpClient();

this._logger.LogDebug($"{nameof(ConnectAsync)} - Connecting");

Expand Down Expand Up @@ -474,7 +484,7 @@ await Task
if (!this._tcpClient.Connected)
{
this.SwitchToDisconnected();
this._logger.LogTrace($"{nameof(DataReceiverAsync)} - Client not connected");
this._logger.LogTrace($"{nameof(DataReceiverAsync)} - TcpClient not connected");

await Task
.Delay(defaultTimeout, cancellationToken)
Expand Down Expand Up @@ -610,13 +620,13 @@ private async Task<byte[]> DataReadAsync(CancellationToken cancellationToken)
if (this._stream == null)
{
this._logger.LogError($"{nameof(DataReadAsync)} - Stream is null");
return Array.Empty<byte>();
return [];
}

if (!this._stream.CanRead)
{
this._logger.LogError($"{nameof(DataReadAsync)} - Stream CanRead is false");
return Array.Empty<byte>();
return [];
}

try
Expand All @@ -628,7 +638,7 @@ private async Task<byte[]> DataReadAsync(CancellationToken cancellationToken)
var numberOfBytesToRead = await this._stream.ReadAsync(this._receiveBuffer.AsMemory(0, this._receiveBuffer.Length), cancellationToken).ConfigureAwait(false);
if (numberOfBytesToRead == 0)
{
return Array.Empty<byte>();
return [];
}

this._logger.LogTrace($"{nameof(DataReadAsync)} - NumberOfBytesToRead:{numberOfBytesToRead}");
Expand All @@ -643,7 +653,7 @@ private async Task<byte[]> DataReadAsync(CancellationToken cancellationToken)
var numberOfBytesToRead = await this._stream.ReadAsync(this._receiveBuffer, 0, this._receiveBuffer.Length, cancellationToken).ConfigureAwait(false);
if (numberOfBytesToRead == 0)
{
return Array.Empty<byte>();
return [];
}

this._logger.LogTrace($"{nameof(DataReadAsync)} - NumberOfBytesToRead:{numberOfBytesToRead}");
Expand All @@ -667,7 +677,7 @@ private async Task<byte[]> DataReadAsync(CancellationToken cancellationToken)
throw;
}

return Array.Empty<byte>();
return [];
}
}
}
24 changes: 22 additions & 2 deletions src/Nager.TcpClient/TcpClientConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,28 @@
public class TcpClientConfig
{
/// <summary>
/// ReceiveBufferSize
/// Receive Buffer Size
/// </summary>
public int ReceiveBufferSize { get; set; } = 1024;
public int ReceiveBufferSize { get; set; } = 8192;

/// <summary>
/// Receive Timeout
/// </summary>
public int ReceiveTimeout { get; set; } = 0;

/// <summary>
/// Send Buffer Size
/// </summary>
public int SendBufferSize { get; set; } = 8192;

/// <summary>
/// Send Timeout
/// </summary>
public int SendTimeout { get; set; } = 0;

/// <summary>
/// No Delay
/// </summary>
public bool NoDelay = false;
}
}

0 comments on commit ecfc69b

Please sign in to comment.