WCF:Net.TCP多绑定,同一端口,不同IP地址

9

我遇到了一个问题。我对WCF还不太熟悉,希望能得到帮助。

以下是我的代码:

public static void StartHosts()
    {
        try
        {
            // Create a new host
            ServiceHost host = new ServiceHost(typeof(ServerTasks));

            List<IPAddress> ips = new List<IPAddress>(Dns.GetHostAddresses(Dns.GetHostName()));
            if (IPAddress.Loopback != null)
                ips.Add(IPAddress.Loopback);

            ips.RemoveAll(i => i.AddressFamily != AddressFamily.InterNetwork);

            foreach (var ip in ips)
            {
                string uri = string.Empty;

                // Formulate the uri for this host
                uri = string.Format(
                    "net.tcp://{0}:{1}/ServerTasks",
                    ip.ToString(),
                    ServerSettings.Instance.TCPListeningPort
                );


                // Add the endpoint binding
                host.AddServiceEndpoint(
                    typeof(ServerTasks),
                    new NetTcpBinding(SecurityMode.Transport) { TransferMode = TransferMode.Streamed },
                    uri
                );

            }



            // Add the meta data publishing
            var smb = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
            if (smb == null)
                smb = new ServiceMetadataBehavior();

            smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
            host.Description.Behaviors.Add(smb);

            host.AddServiceEndpoint(
                ServiceMetadataBehavior.MexContractName,
                MetadataExchangeBindings.CreateMexTcpBinding(),
                "net.tcp://localhost/ServerTasks/mex"
            );

            // Run the host
            host.Open();
        }
        catch (Exception exc)
        {
            DebugLogger.WriteException(exc);
        }
    }

在代码的“host.Open();”这一行抛出了异常。
异常信息如下: System.InvalidOperationException A registration already exists for URI 'net.tcp://192.168.1.45:4329/ServerTasks'。

我的目标是将服务绑定到机器上的所有网络地址,以便客户端应用程序可以从它们看到的任何网络中访问该服务。运行此代码时,它会查找并尝试设置约5个不同IP的绑定,包括127.0.0.1。
192.168.1.45是它尝试绑定的第二个IP。在它抛出异常的那一点上,我可以通过使用netstat看到该程序已经将第一个IP绑定到端口4329上。在异常中提到的地址上没有任何东西绑定到端口4329。
注意:我已经尝试在foreach循环内创建的NetTcpBinding的PortSharingEnabled属性设置为true,但我仍然遇到了相同的错误。
如果有需要更多信息,请随时联系我。
谢谢!
3个回答

10

感谢您提供的信息,Corazza!

我已经想出如何实现这个目标。我一开始的思路是错误的。

我的最终目标是让服务在机器上的每个可用IP地址上进行监听。尝试逐个绑定每个地址是错误的做法。

相反,我只需要将服务绑定到机器的主机名(而不是'localhost'),WCF会自动监听所有适配器。

以下是更正后的代码:

public static void StartHosts()
    {
        try
        {
            // Formulate the uri for this host
            string uri = string.Format(
                "net.tcp://{0}:{1}/ServerTasks",
                Dns.GetHostName(),
                ServerSettings.Instance.TCPListeningPort
            );

            // Create a new host
            ServiceHost host = new ServiceHost(typeof(ServerTasks), new Uri(uri));

            // Add the endpoint binding
            host.AddServiceEndpoint(
                typeof(ServerTasks),
                new NetTcpBinding(SecurityMode.Transport) 
                        { 
                            TransferMode = TransferMode.Streamed
                        },
                uri
            );

            // Add the meta data publishing
            var smb = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
            if (smb == null)
                smb = new ServiceMetadataBehavior();

            smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
            host.Description.Behaviors.Add(smb);

            host.AddServiceEndpoint(
                ServiceMetadataBehavior.MexContractName,
                MetadataExchangeBindings.CreateMexTcpBinding(),
                "net.tcp://localhost/ServerTasks/mex"
            );

            // Run the host
            host.Open();
        }
        catch (Exception exc)
        {
            DebugLogger.WriteException(exc);
        }
    }

1
将每个IP地址单独绑定是正确的做法,因为否则您的服务器会存在安全漏洞——想象一下(不太可能的)情况:另一个服务绑定到特定主机IP地址和相同端口,而您的服务绑定到所有IP地址。在这种情况下,仿冒者将获得所有来自连接到此IP地址的客户端的连接请求。 - AlexT

2

看起来我有点晚了 :). 但是无论如何 - 有一种非常简单的方法可以使Wcf监听所有可用的网络接口"net.tcp://0.0.0.0:8523/WCFTestService"。


2

Mel,

虽然我自己从未尝试过这种方法,但以下是一些我听到过的示例。你可能需要先创建绑定对象,然后将同一实例添加到AddServiceEndpoint方法中,这样就不必每次都创建新的绑定。我记得在某个地方读到,netTCPBindings应该与地址呈1:1关系(即使你使用不同的地址),所以你可以考虑这个想法。

我认为你无需担心端口共享问题,因为你正在开放多个端口。

以下是使用多个端口的示例:

http://www.aspfree.com/c/a/Windows-Scripting/WCF-and-Bindings/2/

以下是使用NetTcpBinding进行端口共享的好例子:

http://blogs.msdn.com/drnick/archive/2006/08/08/690333.aspx

-Bryan


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接