Udp-прослушиватель «пакетирует» на MacOSC#

Место общения программистов C#
Ответить
Anonymous
 Udp-прослушиватель «пакетирует» на MacOS

Сообщение Anonymous »

Вот мой код в моей функции прослушивателя.

Код: Выделить всё

while (!stoppingToken.IsCancellationRequested)
{
try
{
if (_udpClient == null)
{
// Explicit binding to match DDPHelper robustness
var localEP = new IPEndPoint(IPAddress.Any, ListenPort);
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);

// CRITICAL: Increase receive buffer size for high-frequency UDP on macOS
// Default macOS buffer may be too small, causing packet delays/drops
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, 96); // 256KB

socket.Bind(localEP);

_udpClient = new UdpClient { Client = socket };

// Log actual buffer size (OS may override our request)
var actualBufferSize = (int)socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer)!;
Console.WriteLine($"UDP Service: Bound successfully. Receive buffer: {actualBufferSize} bytes");

_fpsWatch.Start();
}

// 2. Processing Loop - CRITICAL: Use synchronous receive to prevent macOS kernel batching
while (!stoppingToken.IsCancellationRequested && _udpClient != null)
{
try
{
// CRITICAL FIX: Synchronous Receive() instead of ReceiveAsync()
// macOS batches async UDP receives at kernel level, causing jerky delivery
if (_udpClient.Available > 0)
{
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
byte[] buffer = _udpClient.Receive(ref remoteEP);

if (buffer.Length == 96)
{
LastFrame = buffer;
_frameCount++;

// Log FPS every 60 frames to diagnose UDP receive rate
if (_frameCount % 60 == 0)
{
double fps = _frameCount / _fpsWatch.Elapsed.TotalSeconds;
Console.WriteLine($"UDP Receive FPS: {fps:F1} ({_frameCount} frames in {_fpsWatch.Elapsed.TotalSeconds:F1}s)");
}

// Send directly to WebSocket clients - no throttling
MusicDongleWebSocketHandler.BroadcastFrame(buffer);
}
}
else
{
// No data available, yield to prevent busy-waiting
await Task.Delay(1, stoppingToken);
}
}
catch (OperationCanceledException)
{
break; // Stopping
}
catch (SocketException sex)
{
Console.WriteLine($"UDP Socket Error: {sex.Message}. Reinitializing...");
_udpClient?.Dispose();
_udpClient = null;
break; // Break info loop to re-bind
}
catch (Exception ex)
{
Console.WriteLine($"UDP Packet Error: {ex.Message}");
await Task.Delay(100, stoppingToken);
}
}
}
catch (Exception ex)
{
Console.WriteLine($"UDP Bind/Outer Error: {ex.Message}. Retrying in 5s...");
_udpClient?.Dispose();
_udpClient = null;
// Wait before retrying bind
await Task.Delay(5000, stoppingToken);
}
}

Console.WriteLine("UDP Service: Stopping...");
_udpClient?.Dispose();
Если я запускаю эту функцию в Windows, я без проблем получаю пакеты со скоростью 30 кадров в секунду.
Однако, если я запускаю эту функцию в macOS, кажется, что она каким-то образом буферизуется. Мои пакеты всегда содержат 96 байт данных и приходят со скоростью 30 кадров в секунду, и я не смог предотвратить потерю кадров. Я попробовал множество вещей, в том числе сделал его синхронным вместо асинхронного, а также протестировал его с полной переработкой, чтобы он работал в старом стиле, где каждый полученный кадр создает новое событие.
Может ли кто-нибудь дать мне некоторое представление о том, как заставить буфер выдавать мне мои данные по команде?

Подробнее здесь: https://stackoverflow.com/questions/798 ... g-on-macos
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»