Чересчур медленная передача данных по tcp в linux
В моем проекте я работают в основном через TcpClient и получаю его NetworkStream. Непосредственно с NetworkStream взаимодействует этот код:
public class StreamExtractor
{
private static Stopwatch profiler = new Stopwatch();
private readonly Stream _ioStream;
private readonly IContextualSerializationToolKit _serializationToolkit;
private const int BufferSize = ushort.MaxValue;
private readonly Memory<byte> _buffer = new byte[BufferSize];
private bool _manualConnectionState = true;
private readonly IEndPointContext _context;
public StreamExtractor(Stream ioStream, IContextualSerializationToolKit serializationToolkit,
IEndPointContext context)
{
_ioStream = ioStream;
_serializationToolkit = serializationToolkit;
_context = context;
profiler.Start();
}
public Action<NetworkMessageHeader> MessageReceived = _ => { };
private ushort ReadMessageLength()
{
var firstByte = _ioStream.ReadByte();
if (firstByte == -1)
{
_manualConnectionState = false;
throw new EndOfStreamException();
}
_manualConnectionState = true;
var secondByte = (byte)_ioStream.ReadByte();
var len = BitConverter.ToUInt16(new[] { (byte)firstByte, secondByte });
return len;
}
public async Task SingleReceive(CancellationToken token = default)
{
Console.WriteLine($"Receive start. Time: {profiler.ElapsedMilliseconds}ms");
var len = ReadMessageLength();
Console.WriteLine($"Received len {len}. Time: {profiler.ElapsedMilliseconds}ms");
var localSpan = _buffer[..len];
await _ioStream.ReadExactlyAsync(localSpan, cancellationToken: token);
Console.WriteLine($"Received. Time: {profiler.ElapsedMilliseconds}ms");
profiler.Restart();
var message = _serializationToolkit.Deserialize<NetworkMessageHeader>(localSpan, _context);
MessageReceived(message);
}
public async Task LoopedReceive(CancellationToken token = default)
{
while (token.IsCancellationRequested == false && IsConnected)
{
await SingleReceive(token);
}
}
private async Task Send(NetworkMessageHeader message, CancellationToken token = default)
{
var rawMessage = _serializationToolkit.Serialize(message, _context);
var header = BitConverter.GetBytes((ushort)rawMessage.Length).AsMemory(0, sizeof(ushort));
Console.WriteLine($"Send start. Time: {profiler.ElapsedMilliseconds}ms");
await _ioStream.WriteAsync(header, token);
await _ioStream.WriteAsync(rawMessage, token);
Console.WriteLine($"Send. Time: {profiler.ElapsedMilliseconds}ms");
profiler.Restart();
}
public async Task SendFromChannel(ChannelReader<NetworkMessageHeader> channel,
CancellationToken token = default)
{
while (token.IsCancellationRequested == false && IsConnected)
{
var message = await channel.ReadAsync(token);
await Send(message, token);
}
}
public bool IsConnected => _ioStream is { CanRead: true, CanWrite: true } && _manualConnectionState;
}
Изначально, то время, на которое я ориентируюсь это время пинг понга gRPC. Когда я запускал прогон теста в консольном приложении используя Windows 11, время отклика в моем случае было около или немного больше чем в gRPC: где то 0.1 мс. Но недавно я установил себе Pop!_OS 22.04 и вначале я ничего не заметил, до тех пор пока не прогнал тест нагрузки который просто не заканчивался. Позже выяснилось что каждый вызов в моей библиотеке занимал примерно 40!!! миллисекунд при отладке в релизном режиме, хотя по сводке теста среднее время при запуске состовляет +-85 мс. Я попробовал запустить этот же тест на виртуалке, и все опять было в норме, ожидаемое время или что то около того.
Я решил собрать доп информацию по длительности операций ввода и вывода, на сервере все было в рамках нормы, практически моментальный отклик, но на клиенте появились те самые большие цифры задержки:
Send start. Time: 11ms
Send. Time: 11ms
Received len 39. Time: 49ms
Received. Time: 90ms
Receive start. Time: 0ms
Send start. Time: 3ms
Send. Time: 3ms
Received len 39. Time: 41ms
Received. Time: 82ms
Receive start. Time: 0ms
Send start. Time: 1ms
Send. Time: 1ms
Received len 39. Time: 42ms
Received. Time: 82ms
Receive start. Time: 0ms
Send start. Time: 0ms
Send. Time: 0ms
Received len 39. Time: 41ms
Received. Time: 82ms
Receive start. Time: 0ms
Send start. Time: 0ms
Send. Time: 0ms
Received len 39. Time: 41ms
Received. Time: 81ms
Receive start. Time: 0ms
Send start. Time: 0ms
Send. Time: 0ms
Received len 39. Time: 40ms
Received. Time: 81ms
Receive start. Time: 0ms
Send start. Time: 0ms
Send. Time: 0ms
Received len 39. Time: 41ms
Received. Time: 81ms
Receive start. Time: 0ms
Send start. Time: 0ms
Send. Time: 0ms
Received len 39. Time: 41ms
Received. Time: 81ms
Receive start. Time: 0ms
Send start. Time: 0ms
Send. Time: 0ms
Received len 39. Time: 42ms
Received. Time: 82ms
Receive start. Time: 0ms
Send start. Time: 0ms
Send. Time: 0ms
Received len 39. Time: 40ms
Received. Time: 81ms
Receive start. Time: 0ms
В чем же проблема в использовании TCP напрямую? Как можно ускорить передачу данных.