Получите внешний 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-адрес клиенту.
Ответы
Ответ 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, вы можете легко создать его и разместить его самостоятельно - предпочтительно в качестве веб-сервиса, чтобы вы могли сделать простой вызов, совместимый с мылом, из вашего приложения. Вы не обязательно будете делать захват экрана столько, сколько пост за сценой и прочитать ответ.
Ответ 7
Если вам просто нужен IP-адрес, связанный с адаптером, вы можете использовать WMI и класс Win32_NetworkAdapterConfiguration.
http://msdn.microsoft.com/en-us/library/aa394217(VS.85).aspx
Ответ 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), не используя внешнюю "помощь".
Ответ 11
Вы можете в принципе проанализировать возвращаемую страницу, выполнив WebRequest http://whatismyipaddress.com
http://www.dreamincode.net/forums/showtopic24692.htm
Ответ 12
Самый надежный способ сделать это - проверить сайт, например http://checkip.dyndns.org/ или аналогичный, потому что пока вы фактически не выходите наружу в свою сеть, вы не можете найти свой внешний IP-адрес. Однако, hardcoding, такой URL-адрес запрашивает возможный сбой. Вы можете выполнить эту проверку только в том случае, если текущий IP-адрес выглядит как RFC1918 частный адрес (192.168.x.x
, являющийся наиболее знакомым из этих.
В противном случае вы можете реализовать свою собственную аналогичную службу, сидящую вне брандмауэра, поэтому вы, по крайней мере, знаете, если она сломалась.