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

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

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

解决方案:
我找到了一种对我来说非常有效的方法。通过实现自定义 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;
}

然后(当我收到来自客户端的请求时)只需从 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();
}

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

有帮助吗?

解决方案 5

我找到了一种对我来说非常有效的方法。通过实现自定义 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;
}

然后(当我收到来自客户端的请求时)只需从 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();
}

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

其他提示

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

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

因此,真正的问题变成了:“我如何获得2啤酒花的设备面向互联网的IP地址?”答案通常是,您没有;至少在没有使用诸如whatismyip.com之类的您已经放弃的服务的情况下,或者进行一次真正大规模的黑客攻击时,包括将DSL调制解调器密码硬编码到您的应用程序中,并查询DSL调制解调器和屏幕抓取管理页面(上帝保佑您)如果调制解调器被更换过)。

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

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

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

所以:

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。

Jonathan Holland 的答案基本上是正确的,但值得补充的是,Dns.GetHostByName 背后的 API 调用相当耗时,最好缓存结果,以便代码只需调用一次。

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

如果您只需要绑定到适配器的 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 范围)而不使用外部“帮助”。

您基本上可以通过执行 WebRequest 来解析返回的页面 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