WCF自托管服务启动随机报Socket权限错误(10013)排查问询
WCF服务启动随机报Socket 10013错误的排查思路
背景信息
我有AC和XV两个应用,AC作为多个XV实例的控制器,每个XV实例作为服务器供AC发送指令、查询进度与结果。XV实例启动流程如下:
- AC启动自托管WCF服务(PortCallBackService),采用TCP、localhost、端口0及
ListenURIMode.Unique让Windows分配可用端口(为所有XV实例统一配置一次); - AC启动XV进程并传入上述端口作为参数;
- XV启动自托管WCF服务,同样采用TCP、localhost、端口0及
ListenURIMode.Unique获取Windows分配的可用端口(路径与回调服务不同),该服务为有状态服务,启动后创建sessionbound factory; - XV将生成的端口报告给AC,AC记录每个XV实例的对应端口。
问题现象
XV在启动服务宿主时会随机失败(约百次出现一次),抛出错误:
A TCP error (10013: An attempt was made to access a socket in a way forbidden by its access permissions) occurred while listening on IP Endpoint=0.0.0.0:xxxx
端口号每次不同,错误信息无明确指向,无明显规律。
相关代码
//Start the AquatorXV service Uri baseAddress = new Uri("net.tcp://localhost:0/AquatorXVService"); ServiceHost host = new ServiceHost(typeof(AquatorXV.Server.AquatorXVServiceInstance), baseAddress); NetTcpBinding endPointBinding = new NetTcpBinding() { MaxReceivedMessageSize = 2147483647, MaxBufferSize = 2147483647, MaxBufferPoolSize = 2147483647, SendTimeout = TimeSpan.MaxValue, OpenTimeout = new TimeSpan(0, 0, 20) }; ServiceEndpoint endPoint = host.AddServiceEndpoint(typeof(AquatorXVServiceInterface.IAquatorXVServiceInstance), endPointBinding, baseAddress); endPoint.ListenUriMode = ListenUriMode.Unique; ServiceMetadataBehavior metadataBehaviour = host.Description.Behaviors.Find<ServiceMetadataBehavior>(); if (metadataBehaviour == null) { ServiceMetadataBehavior smb = new ServiceMetadataBehavior(); smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15; host.Description.Behaviors.Add(smb); } else { metadataBehaviour.MetadataExporter.PolicyVersion = PolicyVersion.Policy15; } ServiceDebugBehavior debugBehaviour = host.Description.Behaviors.Find<ServiceDebugBehavior>(); if (debugBehaviour == null) host.Description.Behaviors.Add( new ServiceDebugBehavior() { IncludeExceptionDetailInFaults = true }); else if (!debugBehaviour.IncludeExceptionDetailInFaults) debugBehaviour.IncludeExceptionDetailInFaults = true; ServiceBehaviorAttribute behaviourAttribute = host.Description.Behaviors.Find<ServiceBehaviorAttribute>(); if (behaviourAttribute == null) host.Description.Behaviors.Add(new ServiceBehaviorAttribute { AddressFilterMode = AddressFilterMode.Any }); else behaviourAttribute.AddressFilterMode = AddressFilterMode.Any; host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexTcpBinding(), "mex"); try { host.Open(); //<<<<<<<<This the the line that throws the exception } catch (Exception ex) { App.WriteToTestLog(ex.Message); App.WriteToTestLog(ex.StackTrace); throw; } int port = host.ChannelDispatchers.First().Listener.Uri.Port; //Start the session bound factory service Uri sessionBoundFactoryBaseAddress = new Uri("net.tcp://localhost:" + port.ToString() + "/AquatorXVSessionBoundFactoryService"); ServiceHost sessionBoundFactoryHost = new ServiceHost(typeof(AquatorXV.Server.SessionBoundFactory), sessionBoundFactoryBaseAddress); ServiceMetadataBehavior smbFactory = new ServiceMetadataBehavior(); smbFactory.MetadataExporter.PolicyVersion = PolicyVersion.Policy15; sessionBoundFactoryHost.Description.Behaviors.Add(smbFactory); sessionBoundFactoryHost.AddServiceEndpoint(typeof(AquatorXVServiceInterface.ISessionBoundFactory), new NetTcpBinding(), sessionBoundFactoryBaseAddress); sessionBoundFactoryHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexTcpBinding(), "mex"); sessionBoundFactoryHost.Open();
异常调用堆栈
Unhandled Exception: System.ServiceModel.CommunicationException: A TCP error (10013: An attempt was made to access a socket in a way forbidden by its access permissions) occurred while listening on IP Endpoint=0.0.0.0:50124. ---> System.Net.Sockets.SocketException: An attempt was made to access a socket in a way forbidden by its access permissions at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress) at System.Net.Sockets.Socket.Bind(EndPoint localEP) at System.ServiceModel.Channels.TcpChannelListener.ListenAndBind(IPEndPoint localEndpoint) --- End of inner exception stack trace --- at System.ServiceModel.Channels.TcpChannelListener.ListenAndBind(IPEndPoint localEndpoint) at System.ServiceModel.Channels.TcpChannelListener.SetupUniquePort(BindingContext context) at System.ServiceModel.Channels.TcpChannelListener..ctor(TcpTransportBindingElement bindingElement, BindingContext context) at System.ServiceModel.Channels.TcpTransportBindingElement.BuildChannelListener[TChannel](BindingContext context) at System.ServiceModel.Channels.Binding.BuildChannelListener[TChannel](Uri listenUriBaseAddress, String listenUriRelativeAddress, ListenUriMode listenUriMode, BindingParameterCollection parameters) at System.ServiceModel.Description.DispatcherBuilder.MaybeCreateListener(Boolean actuallyCreate, Type[] supportedChannels, Binding binding, BindingParameterCollection parameters, Uri listenUriBaseAddress, String listenUriRelativeAddress, ListenUriMode listenUriMode, ServiceThrottle throttle, IChannelListener& result, Boolean supportContextSession) at System.ServiceModel.Description.DispatcherBuilder.BuildChannelListener(StuffPerListenUriInfo stuff, ServiceHostBase serviceHost, Uri listenUri, ListenUriMode listenUriMode, Boolean supportContextSession, IChannelListener& result) at System.ServiceModel.Description.DispatcherBuilder.InitializeServiceHost(ServiceDescription description, ServiceHostBase serviceHost) at System.ServiceModel.ServiceHostBase.InitializeRuntime() at System.ServiceModel.ServiceHostBase.OnOpen(TimeSpan timeout) at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) at AquatorXV.AquatorControl.StartRemoteServerWCF(Int32 applicationInstanceId, Int32 machineServiceCallBackServicePort) at AquatorXV.App.Main(String[] args)
事件查看器日志
Application: AquatorXV.exe Framework Version: v4.0.30319 Description: The process was terminated due to an unhandled exception. Exception Info: System.Net.Sockets.SocketException at System.Net.Sockets.Socket.DoBind(System.Net.EndPoint, System.Net.SocketAddress) at System.Net.Sockets.Socket.Bind(System.Net.EndPoint) at System.ServiceModel.Channels.TcpChannelListener.ListenAndBind(System.Net.IPEndPoint) Exception Info: System.ServiceModel.CommunicationException at System.ServiceModel.Channels.TcpChannelListener.ListenAndBind(System.Net.IPEndPoint) at System.ServiceModel.Channels.TcpChannelListener.SetupUniquePort(System.ServiceModel.Channels.BindingContext) at System.ServiceModel.Channels.TcpChannelListener..ctor(System.ServiceModel.Channels.TcpTransportBindingElement, System.ServiceModel.Channels.BindingContext) at System.ServiceModel.Channels.TcpTransportBindingElement.BuildChannelListener[[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]](System.ServiceModel.Channels.BindingContext) at System.ServiceModel.Channels.Binding.BuildChannelListener[[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]](System.Uri, System.String, System.ServiceModel.Description.ListenUriMode, System.ServiceModel.Channels.BindingParameterCollection) at System.ServiceModel.Description.DispatcherBuilder.MaybeCreateListener(Boolean, System.Type[], System.ServiceModel.Channels.Binding, System.ServiceModel.Channels.BindingParameterCollection, System.Uri, System.String, System.ServiceModel.Description.ListenUriMode, System.ServiceModel.Dispatcher.ServiceThrottle, System.ServiceModel.Channels.IChannelListener ByRef, Boolean) at System.ServiceModel.Description.DispatcherBuilder.BuildChannelListener(StuffPerListenUriInfo, System.ServiceModel.ServiceHostBase, System.Uri, System.ServiceModel.Description.ListenUriMode, Boolean, System.ServiceModel.Channels.IChannelListener ByRef) at System.ServiceModel.Description.DispatcherBuilder.InitializeServiceHost(System.ServiceModel.Description.ServiceDescription, System.ServiceModel.ServiceHostBase) at System.ServiceModel.ServiceHostBase.InitializeRuntime() at System.ServiceModel.ServiceHostBase.OnOpen(System.TimeSpan) at System.ServiceModel.Channels.CommunicationObject.Open(System.TimeSpan) at AquatorXV.AquatorControl.StartRemoteServerWCF(Int32, Int32) at AquatorXV.App.Main(System.String[])
排查建议
1. 排查端口TIME_WAIT状态冲突
Windows会把关闭的Socket保留在TIME_WAIT状态一段时间(默认240秒),短时间内频繁启动XV可能导致系统分配到这类端口:
- 报错时立刻执行
netstat -ano | findstr :xxxx(替换xxxx为报错端口),查看该端口是否处于TIME_WAIT状态; - 调整TCP参数:修改注册表
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters下的TcpTimedWaitDelay(设为30-60秒),或者扩大动态端口范围(netsh int ipv4 set dynamicport tcp start=49152 num=16384)。
2. 检查权限与安全拦截
- 尝试用管理员权限运行XV,确认是否是普通用户权限不足导致绑定失败;
- 临时关闭防火墙/安全软件,测试是否还会出现错误;
- 检查Windows动态端口范围是否足够:执行
netsh int ipv4 show dynamicport tcp查看,若范围过小可扩大。
3. 排查WCF服务初始化的竞态问题
代码中主服务启动后立刻在同一端口启动sessionBoundFactory服务,虽理论上路径不同不冲突,但可尝试:
- 在
host.Open()后添加短暂延迟(比如Thread.Sleep(100))再启动子服务; - 检查是否有其他线程在操作该端口资源。
4. 调整Socket绑定地址
当前用0.0.0.0监听所有网卡,可能存在网卡异常导致绑定失败:
- 把地址改成
127.0.0.1而非localhost,强制只监听本地回环; - 尝试指定具体物理网卡的IP地址,排除虚拟网卡/VPN的干扰。
5. 检查进程资源泄漏
若XV退出时未正确释放ServiceHost,会导致Socket资源无法回收:
- 在XV退出逻辑中添加
host.Close()和sessionBoundFactoryHost.Close(),最好放在finally块中确保执行; - 用任务管理器查看XV进程退出后是否还有残留的WCF相关线程。
6. 增强错误日志
在catch块中添加更多上下文信息,方便定位:
- 执行
netstat -ano并将输出写入日志; - 记录当前进程的用户权限、系统动态端口范围等信息。
内容的提问来源于stack exchange,提问作者FunkyDexter
相关产品推荐
相关产品推荐

