#c# #winforms #udpclient
#c# #winforms #udpclient
Вопрос:
Я столкнулся с любопытной проблемой, которую, похоже, не могу отладить. Мое приложение получило пакеты от устройства, отправляющего UDP-пакеты через определенный порт. После настройки прослушивателя UDP цикл while периодически запускает команду Receive .
Я должен получать 400 значений за каждый заданный интервал времени, и я даже установил процесс, чтобы убедиться, что эти значения проходят. Ниже приведен фрагмент соответствующего кода:
public UdpClient listener;
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, listenPort);
//where listenPort is an int holding the port values should be received from
listener.ExclusiveAddressUse = false;
listener.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
listener.Client.Bind(groupEP);
if (listener.Client.Connected)
{
listener.Connect(groupEP);
}
//I've actually never seen the app actually enter the code contained above
try
{
while (!done)
{
if (isListenerClosed == false amp;amp; currentDevice.isConnected)
{
try
{
receive_byte_array = listener.Receive(ref groupEP);
}
catch (Exception ex)
{
throw ex;
}
}
}
}
catch (SocketException ex)
{
throw ex;
}
Странно то, что приложение отлично работает на моем компьютере (как через установочный файл / Installshield, так и при запуске в Visual Studio), но не получает никаких данных при запуске установочного файла на компьютере коллеги (он отлично работает в его среде Visual Studio). Я также попытался подключить Visual Studio к процессу приложения, где обнаружил, что код работает нормально, пока не достигнет listener.Receive
. Никакие исключения не перехватываются, никаких ошибок в VS не указано, но код просто останавливается, поскольку данные не получены.
Кстати, обе машины идентичны (Mac Minis под управлением 64-разрядной Windows 7 Ultimate N).
Я даже включил в основную программу обработчик UnhandledExceptionHandler следующим образом:
AppDomain.CurrentDomain.UnhandledException = new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
MessageBox.Show("Unhandled Exception Caught " e.ToString());
throw new NotImplementedException();
}
Может ли это быть проблемой с разрешениями приложений в Windows? Есть идеи о наилучшем подходе к выявлению проблемы?
Комментарии:
1. Возможно, проблема с брандмауэром, вы проверили это?
2. Похоже, что брандмауэр на самом деле блокирует UDP-соединение, но не подключение к Интернету. Чувствую себя глупо, что пропустил это. Спасибо @oleksii !
Ответ №1:
UDP — это протокол без подключения. Не Connect
делайте этого. Вместо этого вы просто передаете пакеты данных. Кроме того, когда вы используете UdpClient
, не копайте до базового сокета. В этом нет смысла.
Самый простой (и довольно глупый) прослушиватель UDP будет выглядеть примерно так:
var listener = new UdpClient(54323, AddressFamily.InterNetwork);
var ep = default(IPEndPoint);
while (!done)
{
var data = listener.Receive(ref ep);
// Process the data
}
Выполнение всех действий вокруг ExclusiveAddressUse
(и SocketOptionName.ReuseAddress
) служит только для того, чтобы скрыть от вас проблемы. Если вы не используете широковещательную передачу или множественное приведение, сообщение получит только один из прослушивателей UDP на этом порту. Обычно это плохо.
Если этот простой код не работает, проверьте конвейер. Брандмауэры, IP-адреса, драйверы и тому подобное. Установите WireShark и убедитесь, что UDP-пакеты действительно проходят — это может быть ошибка устройства, возможно, неправильная конфигурация.
Кроме того, в идеале вы хотели бы делать все это асинхронно. Если у вас .NET 4.5, это на самом деле довольно просто.
Комментарии:
1. Проблема на самом деле оказалась в брандмауэре. Я добавил,
ExclusiveAddressUse
поскольку я продолжал получать исключения SocketExceptions при создании нового прослушивателя (это приложение на основе сеанса). Подключение таким образом и последующее закрытие соединения, похоже, решили проблему, с которой я сталкивался при завершении одного сеанса и запуске другого. Ранее у нас были некоторые проблемы с устройством. Я получал меньше пакетов, чем ожидалось, из-за неисправного компонента, но с тех пор я дважды проверил его, и с ним все в порядке. Интересно, есть ли в любом случае, чтобы приложение было более надежным для брандмауэров2. Брандмауэр Windows по умолчанию блокирует практически все входящие данные, вот так просто. Если вы хотите это изменить, вы можете включить изменение правила брандмауэра как часть вашего установщика. Это то, что делают все надлежащие серверы 🙂 При подключении к Интернету вы создаете исходящее соединение (а TCP является двунаправленным, поэтому вам вообще не нужно входящее соединение), которые разрешены по умолчанию.
3. Для меня это был правильный ответ: не вызывать
Connect
, а отправлять удаленный адрес и порт в функции Send(), напримерudpClient.Send(dgram, dgram.Length, remoteEndPoint);
Ответ №2:
Если вы используете это в Windows Vista или выше, это, вероятно UAC
, . Это может незаметно препятствовать правильной работе сокетов. Если вы уменьшите UAC
уровень, это не просто заблокирует сокет.