Подтвердить что ты не робот

Получите внешний IP-адрес через удаленный доступ в С#

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

В приложении у меня есть соединение (через удаленную передачу .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-адрес клиенту.

4b9b3361

Ответ 1

Я нашел способ, который отлично работал у меня. Внедряя пользовательский 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-адрес клиенту.

Ответ 2

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

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

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

EDIT: теперь, чтобы применить это к рефакторингу, "Как мне получить IP-адрес моего клиента с .NET-компонента сервера?" Как и whatismyip.com, лучшее, что может сделать сервер, это предоставить вам IP-адрес вашего устройства, ориентированного на Интернет, что вряд ли будет фактическим IP-адресом компьютера, на котором запущено приложение. Возвращаясь к моему ноутбуку, если мой IP-адрес, ориентированный на Интернет, был 75.75.75.75, а IP-адрес локальной сети был 192.168.0.112, сервер мог бы видеть только 75.75.75.75 IP-адрес. Это дойдет до моего DSL-модема. Если ваш сервер захотел сделать отдельное подключение обратно к моему ноутбуку, мне сначала нужно было бы настроить DSL-модем и любые маршрутизаторы между ним и моим ноутбуком, чтобы распознавать входящие соединения с вашего сервера и соответствующим образом перенаправлять их. Есть несколько способов сделать это, но это выходит за рамки этой темы.

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

Ответ 3

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

Итак:

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

EDIT:

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

Ответ 4

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

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

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

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

Ответ 5

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

Ответ 6

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

Ответ 8

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

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

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

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

Ответ 9

Хорошо, если у вас есть 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);
}

Удачи.

Ответ 10

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

Ответ 12

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

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