У меня есть приложение C # / WPF, которое отправляет сообщение по UDP 30 раз в секунду.Сообщения отправляются из свободно работающего потока и отправляются на фиксированный IP-адрес.Каждое сообщение разбивается на 1-6 дейтаграмм в зависимости от размера сообщения, поэтому я посылаю от 30 до 180 дейтаграмм в секунду с общей пропускной способностью до ~ 250 кбит / с.Я преследовал проблему, когда скорость отправки из моего приложения иногда резко замедляется.Приложение является многопоточным, и в дополнение к потоку пользовательского интерфейса у меня есть:
- Свободно работающий фоновый поток, который предоставляет данные для отправки по сети на основе собственной внутренней синхронизации.Это добавляет, создает дейтаграммы сообщений и добавляет их в
ConcurrentQueue
вместе с адресом назначения - Фоновый поток отправителя, который читает
ConcurrentQueue
и отправляет дейтаграммы на требуемый адрес через Socket.SendTo
* 1009.*
Для справки, здесь приведена инициализация сокета:
try
{
_Socket?.Close();
_Socket = null;
_Socket = new Socket(SocketType.Dgram, ProtocolType.Udp);
_Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
_Socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, true);
_Socket.EnableBroadcast = true;
_Socket.Bind(_LocalEP);
}
catch (SocketException e)
{
utils.error.SocketExceptionMessage(e, _LocalEP.Address, (UInt16)_LocalEP.Port);
Stop();
}
После долгих поисков теней я выделил поведение для вызова Socket.Sendto
, установив для измерения поток отправителя.время, которое занимает вызов:
private void SendThreadF()
{
Stopwatch sw = new Stopwatch();
sw.Start();
List<long> loopDeltaTs = new List<long>();
long lastLoopTime=0;
while (CanSend)
{
DGMessage m;
while (SendQueue.TryDequeue(out m))
{
if (CanSend)
{
lastLoopTime = sw.ElapsedMilliseconds;
_Socket.SendTo(m.Datagram, m.Length, SocketFlags.None, m.Destination);
loopDeltaTs.Add(sw.ElapsedMilliseconds - lastLoopTime);
}
}
Thread.Sleep(10);
}
Trace.WriteLine("Send Thread is Exiting!");
}
После запуска, позволяя приложению работать в течение минуты или около того, а затем прерывая его, чтобы просмотреть записанные моменты времени, я вижу следующее:
- Почти все вызовы занимают 0-1 миллисекунды, как и ожидалось.
- Каждый 54-й или 55-й вызов занимает 590-598 миллисекунд.
- Этот шаблон, по-видимому, надежно повторяется, пока выполняется поток (десяткитысячи образцов)
- Относительное время с регулярными перерывами с интервалами ~ 600 мс точно соответствует тому, что я вижу в Wireshark
Я уже дважды сталкивался с таким поведением, и каждый раз, когда оно перезагружалось после перезагрузки компьютера.
Вот странная вещь: я перезагрузил компьютер, и проблема прекратилась.Это говорит о том, что это может вообще не иметь никакого отношения к моему приложению, но это все равно будет представлять проблему поддержки пользователей.К сожалению, я в растерянности, как решить эту проблему дальше.
- Есть ли какая-либо причина, по которой это может быть вызвано конфигурацией сокета (хотя я видел эту проблему раньше, когда использовал UdpClient вместо сокетов)?
- Есть ли какой-либо известный способчто другое приложение может получить доступ к тому же порту таким образом, что доступ моего приложения может быть заблокирован?(В Wireshark, FWIW нет соответствующего трафика)
- Есть ли что-нибудь еще, что я могу сделать, чтобы обойти или диагностировать эту проблему, когда она возникает?