Получить внешний IP-адрес через удаленное взаимодействие в C#
Вопрос
мне нужно выяснить внешний 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://checkip.dyndns.org/ или что-то подобное, потому что, пока вы действительно не выйдете за пределы своей сети, вы не сможете найти свой внешний IP-адрес.Однако жесткое кодирование такого URL-адреса может привести к сбою.Возможно, вы захотите выполнить эту проверку только в том случае, если текущий IP-адрес выглядит как RFC1918 частный адрес (192.168.x.x
будучи самым знакомым из них.
В противном случае вы можете реализовать свою собственную аналогичную службу, расположенную вне брандмауэра, так что вы, по крайней мере, будете знать, если она сломана.