Получить внешний IP-адрес через удаленное взаимодействие в C#

StackOverflow https://stackoverflow.com/questions/66363

  •  09-06-2019
  •  | 
  •  

Вопрос

мне нужно выяснить внешний IP-адрес компьютера, на котором запущено приложение C#.

В приложении у меня есть подключение (через удаленное взаимодействие .NET) к серверу.Есть ли хороший способ получить адрес клиента на стороне сервера?

(Я отредактировал вопрос, чтобы было немного понятнее.Прошу прощения у всех добрых людей, которые постарались ответить на вопрос, возможно я выразился слишком расплывчато)

Решение:
Я нашел способ, который мне очень помог.Реализуя собственные IServerChannelSinkProvider и IServerChannelSink, где у меня есть доступ к CommonTransportKeys.IPAddress, можно легко добавить IP-адрес клиента в CallContext.

public ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack, 
    IMessage requestmessage, ITransportHeaders requestHeaders, 
    System.IO.Stream requestStream, out IMessage responseMessage, 
    out ITransportHeaders responseHeaders, out System.IO.Stream responseStream)
{
    try
    {
        // Get the IP address and add it to the call context.
        IPAddress ipAddr = (IPAddress)requestHeaders[CommonTransportKeys.IPAddress];
        CallContext.SetData("ClientIP", ipAddr);
    }
    catch (Exception)
    {
    }

    sinkStack.Push(this, null);
    ServerProcessing srvProc = _NextSink.ProcessMessage(sinkStack, requestmessage, requestHeaders,
        requestStream, out responseMessage, out responseHeaders, out responseStream);

    return srvProc;
}

А позже (когда я получу запрос от клиента) просто получу IP-адрес из CallContext вот так.

public string GetClientIP()
{
    // Get the client IP from the call context.
    object data = CallContext.GetData("ClientIP");

    // If the data is null or not a string, then return an empty string.
    if (data == null || !(data is IPAddress))
        return string.Empty;

    // Return the data as a string.
    return ((IPAddress)data).ToString();
}

Теперь я могу отправить IP обратно клиенту.

Это было полезно?

Решение 5

Я нашел способ, который мне очень помог.Реализуя собственные IServerChannelSinkProvider и IServerChannelSink, где у меня есть доступ к CommonTransportKeys.IPAddress, можно легко добавить IP-адрес клиента в CallContext.

public ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack, 
    IMessage requestmessage, ITransportHeaders requestHeaders, 
    System.IO.Stream requestStream, out IMessage responseMessage, 
    out ITransportHeaders responseHeaders, out System.IO.Stream responseStream)
{
    try
    {
        // Get the IP address and add it to the call context.
        IPAddress ipAddr = (IPAddress)requestHeaders[CommonTransportKeys.IPAddress];
        CallContext.SetData("ClientIP", ipAddr);
    }
    catch (Exception)
    {
    }

    sinkStack.Push(this, null);
    ServerProcessing srvProc = _NextSink.ProcessMessage(sinkStack, requestmessage, requestHeaders,
        requestStream, out responseMessage, out responseHeaders, out responseStream);

    return srvProc;
}

А позже (когда я получу запрос от клиента) просто получу IP-адрес из CallContext вот так.

public string GetClientIP()
{
    // Get the client IP from the call context.
    object data = CallContext.GetData("ClientIP");

    // If the data is null or not a string, then return an empty string.
    if (data == null || !(data is IPAddress))
        return string.Empty;

    // Return the data as a string.
    return ((IPAddress)data).ToString();
}

Теперь я могу отправить IP обратно клиенту.

Другие советы

Это один из тех вопросов, где вам придется заглянуть глубже и, возможно, переосмыслить первоначальную проблему;в данном случае: «Зачем вам внешний IP-адрес?»

Проблема в том, что у компьютера может не быть внешнего IP-адреса.Например, у моего ноутбука есть внутренний IP-адрес (192.168.xy), назначенный маршрутизатором.Сам маршрутизатор имеет внутренний IP-адрес, но его «внешний» IP-адрес также является внутренним.Он используется только для связи с модемом DSL, который на самом деле имеет внешний IP-адрес с выходом в Интернет.

Таким образом, реальным вопросом станет: «Как мне получить IP-адрес с интернетом устройства 2 хмеля?» И ответ вообще, вы этого не делаете;по крайней мере, без использования такого сервиса, как Whatismyip.com, который вы уже закрыли, или без действительно масштабного взлома, включающего жесткое кодирование пароля модема DSL в ваше приложение, запрос модема DSL и очистку экрана страницы администратора (и Бог поможет вам если модем когда-либо будет заменен).

РЕДАКТИРОВАТЬ:Теперь, чтобы применить это к реформированному вопросу: «Как получить IP -адрес моего клиента от компонента .NET Server?» Как и Whatismyip.com, лучшее, что сможет сделать сервер, это предоставить вам IP-адрес вашего устройства, ориентированного на Интернет, который вряд ли будет фактическим IP-адресом компьютера, использующего приложение.Возвращаясь к моему ноутбуку, если бы мой IP-адрес с выходом в Интернет был 75.75.75.75, а IP-адрес локальной сети был 192.168.0.112, сервер мог бы видеть только IP-адрес 75.75.75.75.Это дойдет до моего DSL-модема.Если бы ваш сервер хотел установить отдельное обратное соединение с моим ноутбуком, мне сначала нужно было бы настроить модем DSL и все маршрутизаторы между ним и моим ноутбуком, чтобы распознавать входящие соединения с вашего сервера и соответствующим образом маршрутизировать их.Есть несколько способов сделать это, но это выходит за рамки этой темы.

Если вы на самом деле пытаетесь установить соединение с сервера обратно на клиент, переосмыслите свой дизайн, потому что вы углубляетесь в территорию WTF (или, по крайней мере, значительно усложняете развертывание вашего приложения).

Dns.GetHostEntry(Dns.GetHostName());вернет массив IP-адресов.Первый должен быть внешним IP, остальные будут за NAT.

Так:

IPHostEntry IPHost = Dns.GetHostEntry(Dns.GetHostName());
string externalIP = IPHost.AddressList[0].ToString();

РЕДАКТИРОВАТЬ:

Есть сообщения, что это не работает для некоторых людей.У меня это работает, но, возможно, в зависимости от конфигурации вашей сети это может не работать.

Лучше просто использовать http://www.whatismyip.com/automation/n09230945.asp он выводит IP только для автоматического поиска.

Если вы хотите что-то, что не зависит от кого-то другого, создайте свою собственную страницу. http://www.unkwndesign.com/ip.php это просто быстрый скрипт:

<?php
echo 'Your Public IP is: ' . $_SERVER['REMOTE_ADDR'];
?>

Единственным недостатком здесь является то, что он получит только внешний IP-адрес интерфейса, который использовался для создания запроса.

Ответ Джонатана Холланда в целом верен, но стоит добавить, что вызовы API, лежащие в основе Dns.GetHostByName, отнимают довольно много времени, и рекомендуется кэшировать результаты, чтобы код можно было вызывать только один раз.

Основная проблема заключается в том, что общедоступный IP-адрес не обязательно связан с локальным компьютером, на котором запущено приложение.Транслируется из внутренней сети через фаервол.Чтобы по-настоящему получить общедоступный IP-адрес без опроса локальной сети, необходимо сделать запрос на интернет-страницу и вернуть результат.Если вы не хотите использовать общедоступный сайт типа WhatIsMyIP.com, вы можете легко создать его и разместить самостоятельно — желательно в виде веб-сервиса, чтобы вы могли выполнить простой вызов, совместимый с мылом, из вашего приложения.Вам не обязательно делать снимок экрана, а делать закулисный пост и читать ответ.

Если вам просто нужен IP-адрес, привязанный к адаптеру, вы можете использовать WMI и класс Win32_NetworkAdapterConfiguration.

http://msdn.microsoft.com/en-us/library/aa394217(VS.85).aspx

Решение Патрика работает для меня!

я сделал один важное изменение.В сообщении процесса я установил CallContext используя этот код:

// try to set the call context
LogicalCallContext lcc = (LogicalCallContext)requestMessage.Properties["__CallContext"];
if (lcc != null)
{
    lcc.SetData("ClientIP", ipAddr);
}

Это помещает IP-адрес в правильный CallContext, чтобы его позже можно было получить с помощьюGetClientIP().

Ну, если предположить, что у вас есть System.Net.Sockets.TcpClient подключенный к вашему клиенту, вы можете (на сервере) использовать client.Client.RemoteEndPoint.Это даст вам System.Net.EndPoint указывая на клиента;что должен содержать экземпляр System.Net.IPEndPoint подкласс, хотя я не уверен насчет условий для этого.После приведения к этому вы можете проверить, Address свойство, чтобы получить адрес клиента.

Короче говоря, у нас есть

using (System.Net.Sockets.TcpClient client = whatever) {
    System.Net.EndPoint ep = client.Client.RemoteEndPoint;
    System.Net.IPEndPoint ip = (System.Net.IPEndPoint)ep;
    DoSomethingWith(ip.Address);
}

Удачи.

Я считаю, что теоретически вы не можете сделать это, находясь за маршрутизатором (например,использование недопустимых диапазонов IP-адресов) без использования внешней «помощи».

По сути, вы можете проанализировать возвращаемую страницу, выполнив веб-запрос http://whatismyipaddress.com

http://www.dreamincode.net/forums/showtopic24692.htm

Самый надежный способ сделать это — проверить сайт типа http://checkip.dyndns.org/ или что-то подобное, потому что, пока вы действительно не выйдете за пределы своей сети, вы не сможете найти свой внешний IP-адрес.Однако жесткое кодирование такого URL-адреса может привести к сбою.Возможно, вы захотите выполнить эту проверку только в том случае, если текущий IP-адрес выглядит как RFC1918 частный адрес (192.168.x.x будучи самым знакомым из них.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top