在 C# 中通过远程获取外部 IP 地址

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/66363/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 11:03:01  来源:igfitidea点击:

Get external IP address over remoting in C#

提问by Patrik Svensson

I need to find out the externalIP of the computer a C# application is running on.

我需要找出运行 C# 应用程序的计算机的外部IP。

In the application I have a connection (via .NET remoting) to a server. Is there a good way to get the address of the client on the server side?

在应用程序中,我有一个到服务器的连接(通过 .NET 远程处理)。有没有什么好的方法可以在服务器端获取客户端的地址?

(I have edited the question, to be a little more clear. I'm apologize to all kind people who did their best to respond to the question, when I perhaps was a little too vague)

(我已经编辑了这个问题,更清楚一点。我向所有尽最大努力回答这个问题的好心人道歉,当时我可能有点太含糊了)

Solution:
I found a way that worked great for me. By implementing a custom IServerChannelSinkProvider and IServerChannelSink where I have access to CommonTransportKeys.IPAddress, it's easy to add the client ip on the CallContext.

解决方案:
我找到了一种非常适合我的方法。通过实现自定义的 IServerChannelSinkProvider 和 IServerChannelSink,我可以访问 CommonTransportKeys.IPAddress,很容易在 CallContext 上添加客户端 IP。

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;
}

And then later (when I get a request from a client) just get the IP from the CallContext like this.

然后(当我收到来自客户端的请求时)就像这样从 CallContext 获取 IP。

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();
}

I can now send the IP back to the client.

我现在可以将 IP 发送回客户端。

采纳答案by Patrik Svensson

I found a way that worked great for me. By implementing a custom IServerChannelSinkProvider and IServerChannelSink where I have access to CommonTransportKeys.IPAddress, it's easy to add the client ip on the CallContext.

我找到了一种对我有用的方法。通过实现自定义的 IServerChannelSinkProvider 和 IServerChannelSink,我可以访问 CommonTransportKeys.IPAddress,很容易在 CallContext 上添加客户端 IP。

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;
}

And then later (when I get a request from a client) just get the IP from the CallContext like this.

然后(当我收到来自客户端的请求时)就像这样从 CallContext 获取 IP。

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();
}

I can now send the IP back to the client.

我现在可以将 IP 发送回客户端。

回答by Matt Michielsen

You can basically parse the page returned by doing a WebRequest of http://whatismyipaddress.com

您基本上可以通过执行http://whatismyipaddress.com的 WebRequest 来解析返回的页面

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

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

回答by UnkwnTech

Better to just use http://www.whatismyip.com/automation/n09230945.aspit only outputs the IP just for the automated lookups.

If you want something that does not rely on someone else put up your own page http://www.unkwndesign.com/ip.phpis just a quick script:

最好只使用http://www.whatismyip.com/automation/n09230945.asp它只输出用于自动查找的 IP。

如果你想要一些不依赖别人的东西,把你自己的页面http://www.unkwndesign.com/ip.php只是一个快速脚本:

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

The only downside here is that it will only retrieve the external IP of the interface that was used to create the request.

这里唯一的缺点是它只会检索用于创建请求的接口的外部 IP。

回答by FlySwat

Dns.GetHostEntry(Dns.GetHostName()); will return an array of IP addresses. The first one should be the external IP, the rest will be the ones behind NAT.

Dns.GetHostEntry(Dns.GetHostName()); 将返回一组 IP 地址。第一个应该是外部 IP,其余的将是 NAT 后面的 IP。

So:

所以:

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

EDIT:

编辑:

There are reports that this does not work for some people. It does for me, but perhaps depending on your network configuration, it may not work.

有报道称这对某些人不起作用。它对我有用,但也许取决于您的网络配置,它可能不起作用。

回答by Alex M

The most reliable manner of doing this is checking a site like http://checkip.dyndns.org/or similar, because until you actually go external to your network, you cannot find your external IP. However, hardcoding such a URL is asking for eventual failure. You may wish to only perform this check if the current IP looks like an RFC1918private address (192.168.x.xbeing the most familiar of these.

最可靠的方法是检查像http://checkip.dyndns.org/或类似的站点,因为在您真正进入网络外部之前,您无法找到您的外部 IP。但是,硬编码这样的 URL 会导致最终失败。如果当前 IP 看起来像一个RFC1918私有地址(这192.168.x.x是其中最熟悉的),您可能希望仅执行此检查。

Failing that, you can implement your own, similar, service sitting external to the firewall, so you will at least know if it's broken.

如果做不到这一点,您可以在防火墙外部实现自己的类似服务,因此您至少会知道它是否已损坏。

回答by TimK

If you just want the IP that's bound to the adapter, you can use WMI and the Win32_NetworkAdapterConfiguration class.

如果您只需要绑定到适配器的 IP,您可以使用 WMI 和 Win32_NetworkAdapterConfiguration 类。

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

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

回答by Yes - that Jake.

Jonathan Holland's answer is fundamentally correct, but it's worth adding that the API calls behind Dns.GetHostByName are fairly time consuming and it's a good idea to cache the results so that the code only has to be called once.

Jonathan Holland 的回答从根本上是正确的,但值得补充的是 Dns.GetHostByName 背后的 API 调用相当耗时,并且缓存结果是一个好主意,这样代码只需调用一次。

回答by Eduardo

I believe theoretically you are unable to do such a thing while being behind a router (e.g. using invalid ip ranges) without using an external "help".

我相信理论上你无法在不使用外部“帮助”的情况下在路由器后面(例如使用无效的 ip 范围)做这样的事情。

回答by Nathan Strong

This is one of those questions where you have to look deeper and maybe rethink the original problem; in this case, "Why do you need an external IP address?"

这是您必须更深入地研究并重新思考原始问题的问题之一;在这种情况下,“为什么需要外部 IP 地址?”

The issue is that the computer may not have an external IP address. For example, my laptop has an internal IP address (192.168.x.y) assigned by the router. The router itself has an internal IP address, but its "external" IP address is also internal. It's only used to communicate with the DSL modem, which actually has the external, internet-facing IP address.

问题是计算机可能没有外部 IP 地址。例如,我的笔记本电脑有一个由路由器分配的内部 IP 地址 (192.168.xy)。路由器本身有一个内部 IP 地址,但它的“外部”IP 地址也是内部的。它仅用于与 DSL 调制解调器通信,后者实际上具有面向 Internet 的外部 IP 地址。

So the real question becomes, "How do I get the Internet-facing IP address of a device 2 hops away?" And the answer is generally, you don't; at least not without using a service such as whatismyip.com that you have already dismissed, or doing a really massive hack involving hardcoding the DSL modem password into your application and querying the DSL modem and screen-scraping the admin page (and God help you if the modem is ever replaced).

所以真正的问题变成了,“我如何获得 2 跳以外设备的面向 Internet 的 IP 地址?” 答案通常是,你没有;至少在不使用诸如 whatismyip.com 之类的服务的情况下,您已经关闭,或者进行了真正的大规模黑客攻击,包括将 DSL 调制解调器密码硬编码到您的应用程序中并查询 DSL 调制解调器和屏幕抓取管理页面(上帝会帮助您)如果调制解调器被更换)。

EDIT: Now to apply this towards the refactored question, "How do I get the IP address of my client from a server .NET component?" Like whatismyip.com, the best the server will be able to do is give you the IP address of your internet-facing device, which is unlikely to be the actual IP address of the computer running the application. Going back to my laptop, if my Internet-facing IP was 75.75.75.75 and the LAN IP was 192.168.0.112, the server would only be able to see the 75.75.75.75 IP address. That will get it as far as my DSL modem. If your server wanted to make a separate connection back to my laptop, I would first need to configure the DSL modem and any routers inbetween it and my laptop to recognize incoming connections from your server and route them appropriately. There's a few ways to do this, but it's outside the scope of this topic.

编辑:现在将此应用于重构的问题,“如何从服务器 .NET 组件获取客户端的 IP 地址?” 与 whatismyip.com 一样,服务器所能做的最好的事情就是为您提供面向 Internet 的设备的 IP 地址,这不太可能是运行该应用程序的计算机的实际 IP 地址。回到我的笔记本电脑,如果我面向 Internet 的 IP 是 75.75.75.75,而 LAN IP 是 192.168.0.112,则服务器将只能看到 75.75.75.75 IP 地址。这将达到我的 DSL 调制解调器。如果您的服务器想要与我的笔记本电脑建立单独的连接,我首先需要配置 DSL 调制解调器以及它与我的笔记本电脑之间的任何路由器,以识别来自您的服务器的传入连接并正确路由它们。有几种方法可以做到这一点,但它

If you are in fact trying to make a connection out from the server back to the client, rethink your design because you are delving into WTF territory (or at least, making your application that much harder to deploy).

如果您实际上试图建立从服务器返回到客户端的连接,请重新考虑您的设计,因为您正在深入研究 WTF 领域(或者至少,使您的应用程序更难以部署)。

回答by Nathan Strong

The main issue is the public IP address is not necessarily correlated to the local computer running the application. It is translated from the internal network through the firewall. To truly obtain the public IP without interrogating the local network is to make a request to an internet page and return the result. If you do not want to use a publicly available WhatIsMyIP.com type site you can easily create one and host it yourself - preferably as a webservice so you can make a simple soap compliant call to it from within your application. You wouldn't necessarily do a screen capture as much as a behind the scenes post and read the response.

主要问题是公共 IP 地址不一定与运行应用程序的本地计算机相关。它是通过防火墙从内部网络翻译过来的。不通过查询本地网络,真正获得公网IP,就是向网页请求并返回结果。如果您不想使用公开可用的 WhatIsMyIP.com 类型的站点,您可以轻松创建一个并自行托管 - 最好作为网络服务,以便您可以从应用程序中对其进行简单的符合肥皂标准的调用。您不一定会像在幕后发帖那样进行屏幕截图并阅读回复。

回答by configurator

Well, assuming you have a System.Net.Sockets.TcpClientconnected to your client, you can (on the server) use client.Client.RemoteEndPoint. This will give you a System.Net.EndPointpointing to the client; that shouldcontain an instance of the System.Net.IPEndPointsubclass, though I'm not sure about the conditions for that. After casting to that, you can check it's Addressproperty to get the client's address.

好吧,假设你有一个System.Net.Sockets.TcpClient连接到你的客户端,你可以(在服务器上)使用client.Client.RemoteEndPoint. 这将使您System.Net.EndPoint指向客户端;它应该包含System.Net.IPEndPoint子类的一个实例,尽管我不确定它的条件。转换到那个之后,您可以检查它的Address属性以获取客户端的地址。

In short, we have

简而言之,我们有

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);
}

Good luck.

祝你好运。