排查端口耗尽问题

适用于:Windows 10

TCP 和 UDP 协议基于用于建立连接的端口号运行。 任何需要建立 TCP/UDP 连接的应用程序或服务都需要端口。

有两种类型的端口:

  • 临时端口(即动态端口)是默认情况下每台计算机都有其建立出站连接的端口集。
  • 已知端口是特定应用程序或服务的定义端口。 例如,文件服务器服务位于端口 445 上,HTTPS 为 443,HTTP 为 80,RPC 为 135。 自定义应用程序还将具有其定义的端口号。

与应用程序或服务建立连接时,客户端设备使用设备中的临时端口连接到为该应用程序或服务定义的已知端口。 客户端计算机上的浏览器将使用临时端口连接到 https://www.microsoft.com 端口 443。

在同一浏览器创建多个与多个网站的连接的情况下,对于浏览器尝试的任何新连接,将使用临时端口。 一段时间后,你会注意到连接将开始失败,发生此故障的可能性很大,这是因为浏览器已使用所有可用端口在外部建立连接,任何建立连接的新尝试都将失败,因为没有更多可用的端口。 使用计算机上的所有端口时,我们将其称为端口耗尽。

TCP/IP 的默认动态端口范围

为了遵守 Internet 分配号码颁发机构 (IANA) 建议,Microsoft 增加了传出连接的动态客户端端口范围。 新的默认起始端口为 49152,新的默认端口为 65535。 此增加是对使用默认端口范围为 1025 到 5000 的早期版本 Windows 的配置的更改。

可以使用以下 netsh 命令查看计算机上的动态端口范围:

  • netsh int ipv4 show dynamicport tcp
    
  • netsh int ipv4 show dynamicport udp
    
  • netsh int ipv6 show dynamicport tcp
    
  • netsh int ipv6 show dynamicport udp
    

每个传输 (TCP 或 UDP) 分别设置范围。 端口范围现在是一个具有起点和结束点的范围。 如果在内部网络上使用防火墙,则部署运行 Windows Server 的服务器的 Microsoft 客户可能会遇到影响服务器之间的 RPC 通信的问题。 在这些情况下,我们建议重新配置防火墙,以允许 49152 到 65535 的动态端口范围内的服务器之间的流量。 此范围除了服务和应用程序使用的已知端口之外。 或者,服务器使用的端口范围可以在每个服务器上进行修改。 使用 netsh 命令调整此范围,如下所示。 上述命令设置 TCP 的动态端口范围。

netsh int <ipv4|ipv6> set dynamic <tcp|udp> start=number num=range

起始端口为数字,端口总数为范围。 下面是示例命令:

  • netsh int ipv4 set dynamicport tcp start=10000 num=1000
    
  • netsh int ipv4 set dynamicport udp start=10000 num=1000
    
  • netsh int ipv6 set dynamicport tcp start=10000 num=1000
    
  • netsh int ipv6 set dynamicport udp start=10000 num=1000
    

这些示例命令将动态端口范围设置为从端口 10000 开始,到端口 10999 端口结束 (1000 个端口) 。 可设置的最小端口范围为 255。 可以设置的最小起始端口为 1025。 基于) 配置的范围的最大端口 (不能超过 65535。 若要复制 Windows Server 2003 的默认行为,请使用 1025 作为起始端口,然后使用 3976 作为 TCP 和 UDP 的范围。 此使用模式会导致起始端口为 1025,端口为 5000。

具体而言,将出站连接视为传入连接不需要临时端口来接受连接。

由于出站连接开始失败,你将看到以下行为的许多实例:

  • 无法使用域凭据登录到计算机,但使用本地帐户登录的工作原理。 域登录需要联系 DC 进行身份验证,这又是出站连接。 如果已设置缓存凭据,则域登录可能仍有效。

    事件查看器中 NETLOGON 错误的屏幕截图。

  • 组策略更新失败:

    故障组策略事件属性的屏幕截图。

  • 无法访问文件共享:

    Windows 无法访问的错误消息的屏幕截图。

  • 受影响服务器的 RDP 失败:

    远程桌面无法连接时出错的屏幕截图。

  • 计算机上运行的任何其他应用程序将开始发出错误

重新启动服务器将暂时解决此问题,但你会看到所有症状在一段时间后恢复。

如果怀疑计算机处于端口耗尽状态:

  1. 尝试建立出站连接。 从服务器/计算机访问远程共享,或尝试将 RDP 连接到另一台服务器或端口上的服务器。 如果所有这些选项的出站连接失败,请转到下一步。

  2. 打开事件查看器并在系统日志下查找清楚地指示当前状态的事件:

    1. 事件 ID 4227

      事件查看器中事件 ID 4227 的屏幕截图。

    2. 事件 ID 4231

      事件查看器中事件 ID 4231 的屏幕截图。

  3. netstat -anob从服务器收集输出。 netstat 输出将显示用于单个 PID 的TIME_WAIT状态的大量条目。

    netstate 命令输出的屏幕截图。

    正常关闭或会话突然关闭后,经过 4 分钟的 (默认) 后,进程或应用程序使用的端口将释放回可用池。 在这 4 分钟内,TCP 连接状态将TIME_WAIT状态。 在怀疑端口耗尽的情况下,应用程序或进程将无法释放它已使用的所有端口,并且将保持TIME_WAIT状态。

    可能还会在同一输出中看到CLOSE_WAIT状态连接;但是,CLOSE_WAIT状态是在 TCP 对等互连的一侧没有其他数据发送 (FIN 发送) 但能够从另一端接收数据时状态。 此状态不一定表示端口耗尽。

    注意

    在TIME_WAIT状态下建立大型连接并不总是指示服务器当前已退出端口,除非验证了前两个点。 拥有大量TIME_WAIT连接确实表明该过程正在创建大量 TCP 连接,最终可能导致端口耗尽。

    Netstat 已在 Windows 10 中更新,并添加-Q了开关以显示已过时等待的端口,如在 BOUND 状态下一样。 已发布包含此功能的 Windows 8.1 和 Windows Server 2012 R2 的更新。 Windows 10中的 PowerShell cmdlet Get-NetTCPConnection 也显示这些 BOUND 端口。

    直到 2016 年 10 月,netstat 不准确。 netstat 的修复,后端移植到 2012 R2,允许Netstat.exe并在 Get-NetTcpConnection Windows Server 2012 R2 中正确报告 TCP 或 UDP 端口使用情况。 请参阅Windows Server 2012 R2:临时端口修补程序以了解详细信息。

  4. 在管理模式下打开命令提示符并运行以下命令。

    Netsh trace start scenario=netconnection capture=yes tracefile=c:\Server.etl
    
  5. 使用网络监视器打开 server.etl 文件,并在筛选器部分中应用筛选器Wscore_MicrosoftWindowsWinsockAFD.AFD_EVENT_BIND.Status.LENTStatus.Code == 0x209。 应该会看到 STATUS_TOO_MANY_ADDRESSES的条目。 如果找不到任何条目,则服务器仍不会退出端口。 如果找到它们,则可以确认服务器处于端口耗尽之下。

排查端口耗尽问题

关键是确定哪个进程或应用程序正在使用所有端口。 下面是一些可用于隔离到单个进程的工具

方法 1

首先查看 netstat 输出。 如果使用的是Windows 10或Windows Server 2016,则可以运行该命令netstat -anobq并检查最大条目为 BOUND 的进程 ID。 或者,还可以运行以下 PowerShell 命令来标识进程:

Get-NetTCPConnection | Group-Object -Property State, OwningProcess | Select -Property Count, Name, @{Name="ProcessName";Expression={(Get-Process -PID ($_.Name.Split(',')[-1].Trim(' '))).Name}}, Group | Sort Count -Descending 

大多数端口泄漏都是由于遇到错误时用户模式进程未正确关闭端口造成的。 在用户模式级别,端口 (实际套接字) 是句柄。 TaskManagerProcessExplorer 都能够显示句柄计数,这使你可以识别哪个进程正在消耗所有端口。

对于 Windows 7 和 Windows Server 2008 R2,可以更新 PowerShell 版本以包括上述 cmdlet。

方法 2

如果方法 1 在Windows 10之前无法识别进程 (并Windows Server 2012 R2) ,请查看任务管理器:

  1. 在详细信息/进程下添加名为“handles”的列。

  2. 对列句柄进行排序,以标识句柄数量最多的进程。 通常,句柄大于 3000 的进程可能是罪魁祸首,但系统、 lsass.exestore.exesqlsvr.exe等进程除外。

    Windows 任务管理器中的句柄列的屏幕截图。

  3. 如果这些进程以外的任何其他进程具有更高的数字,请停止该进程,然后尝试使用域凭据登录,并查看它是否成功。

方法 3

如果任务管理器不帮助你识别进程,请使用进程资源管理器来调查问题。

使用进程资源管理器的步骤:

  1. 下载进程资源管理器并将其运行

  2. Alt + 选择列标题, 选择“选择列”,然后在 “进程性能 ”选项卡上添加 句柄计数

  3. 选择 “视图>显示下窗格”。

  4. 选择 “查看>下窗格”视图>句柄

  5. 选择要按该值排序 的 Handles 列。

  6. 如果无法建立出站连接) ,检查句柄计数高于其余 (可能超过 10,000 个进程。

  7. 单击此项可突出显示句柄计数较高的进程之一。

  8. 在下窗格中,下面列出的句柄是套接字。 (套接字在技术上是文件句柄) 。

    文件 \Device\AFD

    进程资源管理器的屏幕截图,其中包含按句柄排序的进程。

  9. 有些是正常的,但大量不是 (成千上万) 。 关闭有关进程。 如果这还原了出站连接,则你已进一步证明应用是原因。 联系该应用的供应商。

最后,如果上述方法不帮助你隔离进程,我们建议你收集处于问题状态的计算机的完整内存转储。 转储会告诉你哪个进程具有最大句柄。

作为一种解决方法,重新启动计算机会使其恢复到正常状态,并有助于暂时解决问题。 但是,当重新启动不切实际时,还可以考虑使用以下命令增加计算机上的端口数:

netsh int ipv4 set dynamicport tcp start=10000 num=1000

此命令将动态端口范围设置为从端口 10000 开始,到端口 10999 端口结束 (1000 个端口) 。 可设置的最小端口范围为 255。 可以设置的最小起始端口为 1025。 基于) 配置的范围的最大端口 (不能超过 65535。

注意

请注意,增加动态端口范围不是永久性的解决方案,而只是暂时的。 你需要跟踪哪些进程/处理器正在消耗最大数量的端口,并从该进程的角度进行故障排除,了解它使用如此多的端口的原因。

对于 Windows 7 和 Windows Server 2008 R2,可以使用以下脚本以定义的频率收集 netstat 输出。 从输出中,可以看到端口使用趋势。

@ECHO ON
set v=%1
:loop
set /a v+=1
ECHO %date% %time% >> netstat.txt
netstat -ano >> netstat.txt
 
PING 1.1.1.1 -n 1 -w 60000 >NUL
 
goto loop

更多信息

  • 端口耗尽和你! - 本文详细介绍了 netstat 状态以及如何使用 netstat 输出来确定端口状态
  • 检测临时端口耗尽:本文具有将在循环中运行的脚本来报告端口状态。 (适用于 Windows 2012 R2、Windows 8、Windows 10 和Windows 11)