【问题标题】:Specify the outgoing IP address to use with WCF client指定要与 WCF 客户端一起使用的传出 IP 地址
【发布时间】:2011-03-16 01:23:42
【问题描述】:

如何定义 WCF 客户端调用 WCF 服务时使用的 LocalEndPoint(如果客户端机器有多个 IP 地址)?

我有一台位于 DMZ 的机器,它有两个 IP 地址,外部 IP 地址可以通过我们位于外部服务提供商处的网络服务器的 VPN 连接通过防火墙访问。在这台机器上运行一个 WCF 和基于 Unity 的自定义应用程序服务器,它应该充当代理或应用程序级网关 (ALG)。它应该接受来自 Web 服务器的服务调用,并使用 wcf 客户端工厂重新生成服务调用,将它们转发到局域网中的真实应用服务器。

当使用 wcf 客户端工厂在此代理上重新创建服务调用时,wcf 客户端应使用此机器的第二个内部 IP 地址,因为只有来自此内部 IP 地址的消息才允许通过防火墙到达局域网中的应用服务器。不幸的是,我们的 wcf 客户端代理总是选择使用第一个“外部”IP 地址创建传出消息。我正在寻找一种方法来显式设置 wcf 客户端代理使用的 IP 地址。

我只能找到一个允许定义 LocalEndPoint 或 ClientBaseAddress 的 WCF 绑定元素:CompositeDuplexBindingElement。据我从文档中了解到,此属性旨在告诉服务器将异步回复消息发送到何处,因此它与我正在寻找的设置不同。

任何想法我可以做些什么来找到一个可行的解决方案?

提前感谢您提供任何有用的建议!

这似乎是一个类似的问题,只是使用 TcpClient/Sockets 而不是 WCF: Specify the outgoing IP address to use with TCPClient / Socket in C#

还有一个,这次是关于 SoapClient: Binding a new SoapClient to a specific IP address before sending outgoing request

【问题讨论】:

    标签: wcf ip-address wcf-binding wcf-client


    【解决方案1】:

    我自己很难找到这个问题的答案,所以我会分享我的解决方案,以防其他人过来。

    下面是一个返回 wcf soapservice 的方法。如果可用,代码将尝试使用特定的 IP。我做了这个检查,让它在测试机器上也能正常工作。

        public static proposalSoapClient getService()
        {
            string serviceurl = "http://somesite.dk/proposal.asmx";
            var localIpAddress = IPAddress.Parse("123.123.123.123");
            var hasLocalAddress = Dns.GetHostEntry(Dns.GetHostName()).AddressList.Any(ip => ip.AddressFamily == AddressFamily.InterNetwork && ip.Equals(localIpAddress));
    
            var binding = new System.ServiceModel.BasicHttpBinding("proposalSoap"); //name of binding in web.config
            var endpoint = new EndpointAddress(serviceurl);
            ServicePoint servicePoint = ServicePointManager.FindServicePoint(new Uri(serviceurl));
            servicePoint.BindIPEndPointDelegate = (sp, rm, retryCount) => { return new IPEndPoint(hasLocalAddress ? localIpAddress : IPAddress.Any, 0); };
            return new proposalSoapClient(binding, endpoint);
        }
    

    此外,当我在测试服务器上时,我必须使用代理才能访问该服务。 (我在可以访问该服务的机器上使用 fiddler 作为代理)。下面是相同的代码,但在测试服务器上添加了代理部分。

        public static proposalSoapClient getService()
        {
            string serviceurl = "http://somesite.dk/proposal.asmx";
            var localIpAddress = IPAddress.Parse("123.123.123.123");
            var hasLocalAddress = Dns.GetHostEntry(Dns.GetHostName()).AddressList.Any(ip => ip.AddressFamily == AddressFamily.InterNetwork && ip.Equals(localIpAddress));
    
            var binding = new System.ServiceModel.BasicHttpBinding("proposalSoap"); //name of binding in web.config
            var endpoint = new EndpointAddress(serviceurl);
            ServicePoint servicePoint = ServicePointManager.FindServicePoint(new Uri(serviceurl));
    
        #if DEBUG
            Uri proxyUri = new Uri("http://someothersite.dk:8888");
            binding.ProxyAddress = proxyUri;
            binding.BypassProxyOnLocal = false;
            binding.UseDefaultWebProxy = false;
            servicePoint = ServicePointManager.FindServicePoint(serviceurl, new WebProxy(proxyUri, false));
        #endif
    
            servicePoint.BindIPEndPointDelegate = (sp, rm, retryCount) => { return new IPEndPoint(hasLocalAddress ? localIpAddress : IPAddress.Any, 0); };
            return new proposalSoapClient(binding, endpoint);
        }
    

    【讨论】:

    • 嗨..你能告诉我proposalSoapClient类型是什么吗?
    【解决方案2】:

    这是一个较旧的线程,但我有一个建议给任何找到这个线程的人,因为它引导我找到一个稍微不同的解决方案。我们有两个进程需要在同一台服务器上的不同进程上运行。

    问题是每个默认选择绑定到 NIC 的主地址。我们找不到让应用绑定到 NIC 上的辅助地址的方法。

    解决方法是向 VM 添加第二个 NIC,将辅助 IP 移动到第二个 NIC,作为第二个 NIC 的主 IP。在 Windows 中,您不能有两个默认网关(即使它们指向相同的地址)。

    因此,在第二个 NIC 上,我们只分配了 IP 和子网掩码。为了让流量路由到正确的接口,我们添加了一个路由语句,格式如下:

    route add 4.3.2.1 mask 255.255.255.255 1.2.3.4 IF 0x10002
    

    我们需要进程与之通信的主机是4.3.2.1,本地默认网关是1.2.3.4,第二个网卡在路由表中显示为接口号0x10002(来自路由打印)。

    我希望这会有所帮助。因为这个,我多了几根白发。

    【讨论】:

    【解决方案3】:

    对于您想要执行的操作,服务器上的路由表有点混乱。与其尝试在应用程序中对其进行更正,不如调整机器上的接口指标和/或路由表,以更喜欢针对该网络的流量的内部接口。 Here 是一个旧参考,但应该或多或少有效。

    我认为 .NET 套接字不允许您显式选择源接口 - 最接近的是 DontRoute SocketOption,但即使在那里,您也可能必须滚动自定义绑定和传输才能使该选项可用.

    【讨论】:

    • 感谢您的回复和提供的链接,将与我们的网络管理员讨论此问题。关于 Net.Sockets,我认为您对于为传出请求显式设置 IP 地址和端口的选项是错误的。有关详细信息,请参阅这些 msdn 文章:Socket.Bind 方法 - 将 Socket 与本地端点关联。 msdn.microsoft.com/en-us/library/…Public Sub Bind (localEP As EndPoint) IPEndPoint(派生自抽象基调用 EndPoint):msdn.microsoft.com/en-us/library/…
    • 简而言之: > 地址 - 获取或设置端点的 IP 地址。 > Port - 获取或设置端点的端口号。 > AddressFamily - 获取 Internet 协议 (IP) 地址系列。 (覆盖 EndPoint.AddressFamily)我确信可以设置本地机器/网络配置,以便在应用程序没有明确引用机器可以拥有的多个 IP 地址之一的情况下应用自动路由。 (正如您所建议的,再次感谢您的描述和文章指南链接!)
    • 我只是不确定在这种特殊情况下这是否是一种可行的方法。出于安全考虑,不允许从代理机器 ip#1 处的传入流量路由到 ip#2 并进一步到 LAN。除了代理应用程序根据传入请求显式重新生成的数据包。
    • 因此必须以某种方式设置网络/机器路由配置,即在代理应用程序/机器上生成的所有 msg 都会自动路由到 lan,但对于所有传入数据包,行程结束于 ip #1,没有进一步的自动转发,绕过代理应用程序。可能这是可能的,我将不得不与我们的管理员核实。关于这个特定场景有什么进一步的建议吗?在此先感谢您的帮助,太客气了! : )) 来自汉堡的问候,约恩
    猜你喜欢
    • 2011-04-25
    • 2011-01-02
    • 1970-01-01
    • 1970-01-01
    • 2010-09-10
    • 2017-01-17
    • 2011-10-04
    • 1970-01-01
    相关资源
    最近更新 更多