Как узнать, какая конечная точка вызвала SocketException, UdpClient - PullRequest
4 голосов
/ 23 июня 2011

Я использую UdpClient на стороне сервера, и он отправляет данные на сторону клиента (более одного клиента). Внезапно клиент перестает прослушивать порт udp, и сервер получает SocketException, когда вызывается endRecieve или beginRecieve.

Насколько я понимаю, это из-за "ICMP Destination Unreachable", и он просто сообщает серверу, что порт закрыт. Это нормально, но ни одно из исключений SocketException не сообщает мне, из какой это конечной точки.

Как узнать, какая конечная точка закрыта, чтобы сервер прекратил отправку на нее и вызвал дополнительные исключения SocketExceptions?

Или есть ли способ для Udpclient прекратить генерировать эти исключения SocketException, чтобы я мог сделать тайм-аут клиентов, если они не ответят через столько-то секунд.

1 Ответ

0 голосов
/ 30 июня 2011

Я сам имею дело с той же проблемой, поэтому мне будет интересно посмотреть, придет ли кто-нибудь лучшее решение, но сейчас у меня есть пара идей:

У меня есть класс оболочки обертки (давайте назовем его AsyncComm) вокруг моих сокетов, которому передается делегат обработчика исключений от его класса-владельца при его создании. Делегат обработчика исключений принимает аргументы исключения и ссылку на экземпляр AsyncComm, который его выдал. Я тогда положил

try
{
   // Do stuff here
{
catch (Exception e)
{
   CallExceptionHandlerDelegate(e, this);
}

в каждом из моих методов асинхронного обработчика в AsyncComm, чтобы они могли выбросить свои исключения в цепочку. В моем случае обработчик исключений использует ссылку на экземпляр AsyncComm для вызова метода в экземпляре AsyncComm, чтобы сообщить ему о повторной инициализации сокета. Вы можете изменить это поведение на все, что вам нужно сделать, чтобы прекратить непрерывно получать SocketExceptions.

Относительно определения конечной точки, из которой пришло исключение, единственная идея, которая у меня есть сейчас, - это анализ конечной точки с конца строки SocketException.Message, но это выглядит как большой шаг.

Обновление : Это клудж, но он работает. Разберите код ниже, часть из него взята из этого вопроса .

private IPEndPoint parseEndPointFromString(string input)
{
    // Matches 1-255.1-255.1-255.1-255:0-65535. I think.
    const string IPPortRegex = @"(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?):(6553[0-5]|655[0-2]\d|65[0-4]\d\d|6[0-4]\d{3}|[1-5]\d{4}|[1-9]\d{0,3}|0)";

    Match match = Regex.Match(input, IPPortRegex);

    if (match.Success)
    {
        string IPPortString = match.Value;

        string[] ep = IPPortString.Split(':');
        if (ep.Length != 2) throw new FormatException("Invalid endpoint format");
        IPAddress ip;
        if (!IPAddress.TryParse(ep[0], out ip))
        {
            throw new FormatException("Invalid IP address");
        }
        int port;
        if (!int.TryParse(ep[1], out port))
        {
            throw new FormatException("Invalid port");
        }
        return new IPEndPoint(ip, port);
    }
    else
    {
        throw new FormatException("Invalid input string, regex could not find an IP:Port string.");
    }
}
...