среда, 23 сентября 2015 г.

Получение внешнего IP-адреса на C#

Вводная: В одной программе было необходимо получить внешний адрес компьютера. Для решения предварительно погуглил и выяснил, что достаточно известная функция и реализуется просто. Если что искать по запросу в гугл - "C# get public ip external". Первые же ссылки ведут на http://www.codeproject.com/Tips/452024/Getting-the-External-IP-Address и http://stackoverflow.com/questions/3253701/get-public-external-ip-address где и показывается как это можно сделать. В данных примерах получение адреса делается через сервисы checkip.dyndns.org и whatismyip.com. Первоначально с ними и начал работать, но возникло куча осложнений - порой дикие задержки и проблемы с соединением. Постоянная ошибка "System.Net.WebException: Время ожидания операции истекло   в System.Net.HttpWebRequest.GetResponse()"

Решил сделать тоже самое, но с оглядкой на Российскую действительность. Первоначально рассматривал https://2ip.ru но там достаточно тяжелая страница и в итоге выбор пал на Яндекс, а конкретно - http://yandex.ru/internet

Решение:
public class PublicIP
{
  public string Get()
  {
    try
    {
      using (var client = new WebClient())
      {
        var uri = new Uri("http://yandex.ru/internet/");
 
        client.Encoding = Encoding.UTF8;
        client.Proxy = null;
 
        var downloadString = client.DownloadString(uri);
        var first = downloadString.IndexOf("<strong>IP-адрес</strong>: ", StringComparison.Ordinal) + 27;
        var last = downloadString.IndexOf("<strong>Регион по IP-адресу</strong>", StringComparison.Ordinal);
 
        downloadString = downloadString.Substring(first, last - first);
 
        return downloadString;
      }
    }
    catch (Exception msg)
    {
      Console.WriteLine(msg);
      return "";
    }
  }
}

PS: Используется простой разбор строк не потому, что я не знаю о парсерах HTML (Html Agility Pack, Fizzler и тп), а просто потому, что

  • а) в данном случае они избыточны 
  • б) удлиняют выполнение функции примерно на 1-2 секунды
  • в) Ради одного единственного места в программе тащить ещё мегабайт библиотекой ИМХО не корректно
  • г) в итоге кода получается больше :)


PS2: Замеры по сравнению с точно такой же функцией, только которая обращается к CheckIP.dyndns.org

Stopwatch stopWatch = new Stopwatch();
 
stopWatch.Start();
 
var gip = new PublicIP();
Console.WriteLine(gip.Get());
 
stopWatch.Stop();
 
Console.WriteLine("Checkip:  " + stopWatch2.Elapsed);

Методика тестирования - запускается программа. Значение записывается отдельно и так по 5 раз для каждого варианта (CheckIP и Yandex)
checkIP
00:00:01.9662763
00:00:02.1180682
00:00:03.0694474
00:00:02.0939421
00:00:02.1191459
Yandex
00:00:00.3286215
00:00:00.3752536
00:00:00.3639731
00:00:00.3458052
00:00:00.3535228

Комментарии излишни.

PS3: Если вам требуется получать в пределах одного города или провайдера, то проще поднять у себя web-сервер и отдавать от себя. Скорость может быть ещё выше.