我该如何获取WCF服务所侦听的端口?

8

我有一个net.tcp WCF服务,我希望操作系统选择要侦听的端口。因此,在我的URI中将端口设置为0,netstat确认操作系统已选择5000范围内的端口。

在服务进程内部的代码中,我该如何找到实际选择的端口呢?

以下是一些展示我尝试过的代码:

Type serviceType = ...;
Uri address = new Uri("net.tcp://0.0.0.0:0/Service/");
ServiceHost serviceHost = new ServiceHost(serviceType, address);
ServiceEndpoint endPoint = serviceHost.AddServiceEndpoint(type, binding, "");
int port1 = endPoint.ListenUri.Port; // returns 0
int port2 = serviceHost.BaseAddresses.First().Port; // also returns 0

在随机端口上监听服务是相当不寻常的,您想这样做有什么原因吗? - Cocowalla
1
@Cocowalla:该服务是工作进程的一部分,因此可以同时存在多个实例,我们正在寻找不涉及.NET TCP端口共享的解决方案。 - ngoozeff
可能是重复的问题:如何获取WCF服务的监听地址/端口? - mafu
3个回答

11

不确定这是否有帮助,但是在SO上已经有类似的问题:

如何获取WCF服务的监听地址/端口?

以下是提交答案中相关部分,您可能想尝试:

foreach (var channelDispatcher in serviceHost.ChannelDispatchers)
{
            Console.WriteLine(channelDispatcher.Listener.Uri);
}

也许你需要 channelDispatcher.Listener.Uri.Port

希望这可以帮到你!


2
@D Hoerster:不幸的是,它只会返回我传入的URI。感谢您指向其他问题的指针。 - ngoozeff
4
看起来我们有一个获胜者。我还需要设置 endPoint.ListenUriMode = ListenUriMode.Unique; 才能让它工作(并在绑定上禁用端口共享)。 - ngoozeff
你是否调用了Open函数? - BozoJoe

3

一旦服务启动,您可以从Description.Endpoints集合中获取实际创建的端点的完整描述(在调用Open()之后才能使用此功能)。从该集合中,您可以获取地址。不幸的是,您必须对端口进行字符串解析。

这是每次服务打开后我的服务器日志记录的内容。

        serviceHost.Open();

        // Iterate through the endpoints contained in the ServiceDescription 
        System.Text.StringBuilder sb = new System.Text.StringBuilder(string.Format("Active Service Endpoints:{0}", Environment.NewLine), 128);
        foreach (ServiceEndpoint se in serviceHost.Description.Endpoints)
        {
            sb.Append(String.Format("Endpoint:{0}", Environment.NewLine));
            sb.Append(String.Format("\tAddress: {0}{1}", se.Address, Environment.NewLine));
            sb.Append(String.Format("\tBinding: {0}{1}", se.Binding, Environment.NewLine));
            sb.Append(String.Format("\tContract: {0}{1}", se.Contract.Name, Environment.NewLine));
            foreach (IEndpointBehavior behavior in se.Behaviors)
            {
                sb.Append(String.Format("Behavior: {0}{1}", behavior, Environment.NewLine));
            }
        }

        Console.WriteLine(sb.ToString());

1
作为替代方案,您可以自己找到一个免费的端口供WCF使用:
private int FindPort()
{
    IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, 0);

    using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
    {
         socket.Bind(endPoint);
         IPEndPoint local = (IPEndPoint)socket.LocalEndPoint;
         return local.Port;
    }
}

这里获取代码。


1
这不安全。在套接字被处理之后但ServiceHost打开之前,其他人可以夺取端口。因此,该方法可能会偶尔失败。 - BatteryBackupUnit

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