排查端口耗尽问题

             适用于: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 连接到另一个服务器,或者通过 telnet 连接到端口上的服务器。 如果所有这些选项的出站连接都失败,请转到下一步。

  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. 在 details/process 下添加名为“handles”的列。

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

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

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

方法 3

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

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

  1. 下载进程资源管理器 并运行它 “提升”。

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

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

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

  5. 选择“ 处理” 列以按该值排序。

  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)