☰
ComfyUI端口报错10013?Windows保留端口段才是真凶
2026/10/8 15:06:47 网站建设 项目流程

上个月接了个挺奇怪的ComfyUI问题排查单子。对方一台Win11机器,装了多张显卡,打算起多个ComfyUI实例分别跑不同工作流。他原本把端口设置成8188、8288、8388,结果第二个实例一起来直接报PermissionError: [Errno 10013] Permission denied。他以为是端口冲突,挨个往后改,改到8488、8588,依然报同一个10013。这时候才意识到不对劲——所有监听端口全被系统拒绝,等于网络服务直接废了。

这个错误我在Windows服务器上见过很多次,但一次把所有端口“团灭”的情况不算常见。查了一圈之后发现,锅根本不在ComfyUI,而在Windows网络栈内部一个大多数人不太了解的机制:系统保留的动态端口排除段,以及端口权限体系的几个隐藏规则。这篇文章不只丢两条netsh命令给你,我会把“为什么换端口也会10013”“如何一次性看清系统端口分配”“多ComfyUI实例场景下到底怎么规划端口”全部掰开揉碎讲清楚。如果你在Windows上跑ComfyUI遇到同样问题,或者单纯想搞清楚PermissionError 10013到底是什么意思,这篇可以直接照着操作。

1. 报错还原与错误码辨析:10013不是“端口被占”那么简单

1.1 一个连换五个端口仍然10013的现场回放

先说当时看到的现象。对方用的启动方式大概是:

python main.py --listen 0.0.0.0 --port 8188

第二和第三个实例分别换成8288、8388。第一个实例跑得很正常,后面全部启动失败。控制台输出类似:

Starting server Error binding to port 8288: PermissionError: [Errno 10013] Permission denied

很多人看到Permission denied第一反应是管理员权限,第二反应是端口被其他程序占用。但这两条都排掉以后还是10013,问题就很微妙了。我先把当时用过的几条排查命令列出来,你们遇到时可以照抄:

netstat -ano | findstr "8288" tasklist | findstr "PID号码"

如果输出为空或者只有TIME_WAIT状态,说明端口实际上没有进程在监听。当时的8288、8388、8488、8588全都处于“空闲但拒绝绑定”的状态。这已经能得出一个关键结论:拒绝绑定的不是某个应用程序,而是操作系统本身。

1.2 三个容易混淆的错误码,别搞混

Windows下socket绑定最常见的错误码有这几个:

错误码含义常见原因
10048Address already in use端口确实被其他进程占用,最“正常”的冲突
10013WSAEACCES / Permission denied系统认为你没有权限绑定该端口,原因较复杂
10014WSAEFAULT地址参数错误,通常是代码问题,与端口绑定关系不大

因为10048和10013在临床上的表现很像,很多教程会混着讲。但一旦你的ComfyUI端口报的是10013,就别再浪费时间去找占用进程了,应该往系统权限、防火墙、保留端口段三个方向查。顺便说一句,这套错误码并不只出现在Python里,.NET、Node.js、Go写的服务在Windows上也可能用不同文本包装同一个10013,比如某些运行时会把“内部错误状态为10013”这种字样直接抛出来,本质是一样的。

1.3 为什么ComfyUI这么容易吃10013

很多人没意识到一件事:ComfyUI默认端口8188在Windows很多机器上正好处在一个“敏感区域”。ComfyUI常用本机IP或局域网IP方式启动(--listen 0.0.0.0),这会触发Windows的防火墙规则检查和端口排除段检查。更要命的是,如果本机装过Docker、WSL2、Hyper-V或者Windows沙盒,这些组件会向系统注册一大段“被排除的端口范围”。这段范围对普通应用是划走的,ComfyUI这个纯Python socket服务恰好无法绑定这些段的端口。于是一堆端口在netstat看来全部空闲,但bind的时候直接被拒。

需要说明的是,并不是只有装过Docker才会触发。很多Win10/Win11系统上,Windows自带的某些服务(例如WinNAT、特定驱动、蓝牙相关服务)都可能注册保留段。各机器的保留段大小和位置差异很大,同样是8188端口,你在这台机器上能绑定,换一台机器就是10013。这就是为什么ComfyUI端口报10013的求助帖在社区里“时灵时不灵”——根源不在ComfyUI本身,而在系统环境的差异。

2. 常规排查:先做这几件事,把“假权限问题”排除掉

2.1 端口占用检查的正确姿势

虽然10013大概率不是单纯占用,但我还是建议先按正常流程查一遍,避免误判。具体操作分三步:

  1. 用netstat确认端口是否有进程监听。
  2. 如果有LISTENING,记下PID,再用tasklist查是哪个进程。
  3. 如果占用方是系统进程(进程名带SYSTEM、svchost之类),需要进一步确认是不是Windows服务组件保留了端口。

命令:

netstat -ano | findstr "8188"

结果为空说明端口空闲。此时如果启动ComfyUI还是10013,就直接跳过“端口被占”这个假设,进入下一轮排查。这一步的真正意义,是把10013和10048明确分开,避免后续绕远路。

2.2 Windows防火墙与第三方安全软件的影响

接下来看防火墙。很多人以为防火墙只挡入站访问,其实某些安全软件(尤其是各类“管家”“卫士”类软件的网络安全模块)会注入WFP(Windows Filtering Platform)驱动,对端口绑定动作本身做过滤。表现就是服务启动时直接报10013。这种情况在装了第三方杀毒、并开启了“网络防护”功能的机器上比较常见。

快速验证方法:暂时退出第三方安全软件,或者临时关闭当前网络配置文件下的防火墙规则,再启动ComfyUI。如果问题消失,说明是防火墙/安全软件在拦截,需要手动添加放行规则。

提示:临时关防火墙做验证没问题,但验证完一定要记得恢复。不要为了省事长期裸奔,尤其是ComfyUI这类会对外开放监听的服务,风险不值得。

2.3 管理员权限:不是万能药,但确实是第一步

出现10013,很多教程第一句就是“用管理员身份运行”。对一部分情况确实有效——当端口被某个高完整性级别的系统服务占用时,普通权限绑定会被拒,提权后就能过。但对Hyper-V保留段这类系统级排除,管理员也无济于事,因为是操作系统的网络栈在拒绝。

我的建议是:管理员身份运行可以作为快速试错手段,但别把宝全押在它上面。你可以做一个成本极低的实验来剥离问题——用管理员权限打开命令提示符(cmd),运行下面这段Python:

import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) try: s.bind(("0.0.0.0", 8288)) print("可以绑定") except OSError as e: print("错误:", e.errno, e) finally: s.close()

如果管理员权限下可以绑定,说明是普通用户权限受限;如果管理员权限下依然10013,那就别再纠结权限了,基本可以锁定为系统保留端口段或者防火墙驱动拦截,直接跳到后面的终极方案。

3. 最大的幕后黑手:系统排除端口段与动态端口池的冲突

3.1 先理解excludedportrange是什么

Windows为了管理临时端口(也就是应用程序发起对外连接时自动分配的源端口),维护了一个动态端口池。默认情况下,这个池子通常是49152到65535这一大段。与此同时,系统会把某些端口从池子里“排除”掉,不参与动态分配。排除原因很多——Hyper-V的NAT、WSL2的网络、Windows沙盒、ICS服务、甚至某些网卡驱动都会注册。

当你执行查询看到excludedportrange时,看到的就是这些系统组件注册保留的区间。这里有个很关键的机制:这些被排除的端口段,在一定程度上会被系统认为是“已保留”,普通应用去listen时,Windows会返回WSAEACCES,也就是10013。换句话说,端口本身没有进程在监听,但系统已经把它划给某个内部组件了,你碰就是权限不足。

3.2 用两条命令看清你机器上的端口格局

这一步非常关键。打开管理员权限的命令提示符,执行:

netsh interface ipv4 show excludedportrange protocol=tcp

我随手在这台笔记本上跑出来的结果是这样的(不同机器差异很大,别拿我的当标准):

协议 TCP 端口排除范围 开始端口 结束端口 ---------- ---------- 1024 1039 1301 1312 3389 3389 5357 5357 5858 5903 9793 9895

每一行都是一段被系统保留的连续端口。注意有些机器还会显示“------------------”开头的Hyper-V保留段,可能直接覆盖好几百甚至上千个端口。如果你的ComfyUI端口正好落在这些段内,那绑定失败就是必然的。

再顺便看下动态端口池:

netsh interface ipv4 show dynamicport tcp

常见输出:

动态端口 tcp -------------- 启动端口 : 49152 端口数量 : 16384

动态端口池本身是正常的临时端口分配区间,ComfyUI绑定这个池内的端口通常不会因此报10013。真正需要警惕的是excludedportrange——它代表系统已经保留的“禁入区”。有些机器因为Hyper-V或WSL的关系,保留段可能从8000多一路延伸到几万,把所有看起来“很合理”的端口全占了,这就是多端口齐翻车的直接原因。

3.3 规划ComfyUI端口前,先画一张“端口地图”

我的习惯是,先把机器上所有excludedportrange记下来,排除掉这些段之后再决定ComfyUI用什么端口。比如当前保留段里有50000到50050这个区间,你又正好把第二个实例配成50050,那10013就是早晚的事。

画地图的实操方法:

  1. 执行netsh interface ipv4 show excludedportrange protocol=tcp。
  2. 把每个区间抄到一个表格里,或者用记事本存一份。
  3. 选择一个不落在任何保留段内的固定端口,作为ComfyUI主端口。
  4. 多个实例时,每个端口都要和保留段做交集检查。

提示:不要盲目相信网上说的“把端口改成8189就行”。如果8189落在你自己机器的保留段里,照样报10013。必须先看自己机器上的排除段,再选端口。

4. 终极组合拳:把ComfyUI的端口从系统层面“焊死”

4.1 方法一:用netsh把特定端口加入排除列表

你可能想反过来用:既然端口不在排除段里,为什么还是10013?有一种情况是,目标端口被某些系统进程临时用作动态源端口,虽然没有LISTENING状态,但端口当前处于TIME_WAIT或已被系统内部占用状态,普通用户绑定时也可能被拒。这时可以把该端口加入系统排除列表,让系统不再把它当动态端口分配:

netsh int ipv4 add excludedportrange protocol=tcp startport=8188 numberofports=1

执行成功后可以用netsh interface ipv4 show excludedportrange protocol=tcp确认。如果提示“无法完成排除范围操作,因为指定的范围与现有排除范围重叠”,说明这个端口本来就已经在保留段里,属于被系统划走的状态——这种情况下别跟系统对着干,直接换端口。

这个方案适用于“端口没有被系统组件硬占用,但频繁被动态临时端口污染”的场景。把ComfyUI端口焊死后,系统不会再把它当作临时端口分配出去,ComfyUI就能长期稳定占用。

4.2 方法二:重设动态端口池,整体挪到安全区间

如果问题是大范围保留段把你要用的端口全吃了——这正是标题里“多端口绑定均报10013”的典型场景——更彻底的做法是重设动态端口池,指定一个避开保留段的区间:

netsh int ipv4 set dynamicport tcp start=49152 num=16384

这条命令把动态临时端口的范围固定为49152到65535。但前提是这段区间要完全避开保留段。如果系统保留段正好覆盖了49152开头的一段,你需要把start改到比如50000。操作前先show excludedportrange看清楚哪些段被占,原则是让新的动态端口池尽量不覆盖这些保留段。

需要注意,修改动态端口池是系统级配置,对大量并发出站连接的应用会有影响,但ComfyUI这种主要监听固定端口的场景,影响很小。改错的话可以用下面这条恢复默认:

netsh int ipv4 set dynamicport tcp start=1025 num=64511

我个人的使用频率排序是:优先“换端口”,其次“焊死特定端口”,最后才动整个动态端口池。毕竟动全池子影响面更大,能不动就不动。

4.3 方法三:URL ACL兜底,专治Windows HTTP端口权限问题

ComfyUI本身不走系统http.sys服务,所以URL ACL在这个场景下大多数时候用不上。但如果你用的是某些基于HTTP.sys的ComfyUI启动器、通过WSL端口转发、或者被其他Windows组件间接绑定,也可能会报10013。此时检查并添加URL ACL是兜底手段:

netsh http show urlacl netsh http add urlacl url=http://+:8188/ user=Everyone

这条命令解决的是“Windows系统HTTP服务对URL的占用权限”问题,不是ComfyUI的日常必需。只有当前面几种方案全部无效时,才建议试一次。

4.4 批处理一键检测多实例端口

如果你需要起多个ComfyUI实例,手动去逐个检查排除段会很痛苦。与其硬记端口号,不如写一个批量检测脚本,启动前自动测试端口可绑定状态。下面这段Python脚本可以直接存下来用:

import socket def port_bindable(port): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) try: s.bind(("0.0.0.0", port)) print(f"端口 {port}: 可绑定") return True except OSError as e: print(f"端口 {port}: errno {e.errno}") return False finally: s.close() for port in range(8188, 8498, 10): port_bindable(port)

这个脚本会从8188开始每隔10个端口测试一次,把10013的端口直接筛掉。测试通过的端口可以作为ComfyUI多实例的候选端口。

5. 多实例场景下的端口冲突:插件、Jupyter与隐藏的系统策略

5.1 ComfyUI-Manager等插件也会偷偷占用端口

多端口10013还有一个容易被忽略的来源:插件自带的服务。比如ComfyUI-Manager的模型下载、云端搜索功能,某些版本在启动时会额外起一个内部HTTP服务,端口是动态选的。如果你手动给多个ComfyUI实例指定了8188、8288、8388,插件内部服务却可能随机落到资源紧张的动态端口段里,最后插件自己先崩了。表面上看起来还是ComfyUI端口绑定报10013,找半天才发现是插件内部子进程。

排查技巧:启动ComfyUI时仔细看控制台完整输出,不要只看第一屏报错。有些插件子进程会打印自己的端口绑定日志。如果确认是插件的问题,找到插件配置文件中关于port或api_port的部分,手动固定一个安全端口,别让它自己去动态池里抢。

5.2 Jupyter/IDE集成环境下的“套娃权限”问题

有些用户喜欢在Jupyter Notebook里直接跑ComfyUI,这也会引出另一类10013。Jupyter进程本身可能没有管理员权限,或者运行在受限环境里。ComfyUI在Notebook里启动时会继承这个受约束的进程token,端口绑定直接失败。JupyterLab的服务器本身可能已经占用了8888这类常用端口,你在Notebook里启动ComfyUI时如果用到同一个端口,也会产生权限冲突。

我的建议是:不要在Jupyter里长期跑ComfyUI服务。开发调试可以用Notebook,生产使用请单独开一个命令行窗口,把ComfyUI作为独立进程运行。如果非得在Jupyter里用,可以先以管理员身份启动Jupyter,并在启动ComfyUI之前用前面那个Python脚本测试目标端口。另外还有个场景就是IDE的端口转发,比如远程开发工具自动占用了目标端口,这种也要排查。

5.3 多显卡多实例的端口规划经验

回到开头的多卡场景。三张显卡起三个实例,合理规划不只是避开保留段,还要考虑未来扩展。我的做法是这样:

  • 固定端口段拆开:实例1用8188,实例2用18188,实例3用28188,拉大端口号距离,避免管理脚本误判。
  • 每个实例额外留出一小段端口给插件和API:比如实例1占8188到8198,实例2占18188到18198。
  • 启动前先用端口检测脚本跑一遍,确认所有端口可用再启动。

如果你有多个网卡,还可以让不同实例绑定不同网卡的IP,进一步降低端口冲突概率。只有一张网卡时,建议用本地回环127.0.0.1绑定,或者通过端口转发访问,这样对外暴露的口子也小一些。

5.4 一个容易被忽视的系统策略问题

另一个容易踩的坑是“隐藏的系统策略限制”。很多人用的ComfyUI整合包是基于venv的绿色包,它启动时用的是venv里的python.exe,这个进程通常继承explorer的权限token。如果explorer本身被某些系统优化软件限了网络相关权限,子进程也会跟着10013。我遇到过一台机器,运行任何需要绑定低端口(小于1024)的程序都会10013,最后发现是系统优化软件把服务账号的本地登录权限全禁了。这种属于隐藏的系统策略问题,靠换端口解决不了。最稳妥的办法是用Process Explorer查看ComfyUI进程的权限和完整性级别,确认是Medium还是High,以及有没有被特殊SID限制。

6. 排错决策清单与我的维护习惯

6.1 一页纸排错流程

把整篇文章浓缩成一段可以直接照着做的排查路径:

  1. 报10013先不要慌,不要反复改端口硬试。
  2. 执行netstat -ano | findstr "端口号",确认端口是否空闲。
  3. 切换到管理员命令行,执行netsh interface ipv4 show excludedportrange protocol=tcp,检查端口是否落在保留段内。
  4. 如果落在保留段内:换一个不在保留段内的端口,或按第4.2节的方案调整动态端口池。
  5. 如果不在保留段内:临时关闭防火墙和第三方安全软件再试。
  6. 在管理员权限下用Python socket脚本测试目标端口绑定。
  7. 仍然失败:检查URL ACL、检查进程完整性级别、检查是否有WFP驱动拦截。

6.2 几条预防性配置

我现在拿到新机器后,会顺手做几件小事,减少以后踩坑的概率:

  • 启动ComfyUI之前,先保存一份excludedportrange和dynamicport的端口地图。
  • 固定ComfyUI端口时,刻意避开地图中的任何区间,并保留一定余量。
  • 对ComfyUI统一使用bat或Python启动器,启动时自动检测端口可用性,失败则自动挑选备用端口并写日志。
  • 如果机器需要同时开Hyper-V/WSL,就把ComfyUI端口规划在完全不会被保留的高段区间,比如50000以上但避开保留段。
  • 多实例场景下,所有实例的端口都经过检测脚本确认,不落到同一保留段内。

6.3 几句实在话

个人经验来说,Windows下的10013和Linux下的EACCES不一样,Windows把“临时端口池管理”“系统保留区”“WFP驱动过滤”“完整性级别”全部搅在一起,排查起来确实绕。ComfyUI本身是无辜的,它在任何端口上都只是调用了bind。真正的问题在于你的Windows环境给不给你bind。与其纠结“为什么8188不行8189行”,不如花五分钟把端口地图看清楚,一劳永逸。

最后再分享我个人最常用的命令组合:

netstat -ano | findstr "端口号" netsh interface ipv4 show excludedportrange protocol=tcp netsh interface ipv4 show dynamicport tcp

这三条命令基本解决了我在Windows上遇到的所有ComfyUI端口绑定问题。先查占用,再看保留段,最后确认动态池,一套下来10分钟就能定位问题。希望这篇排障记录能帮你少走点弯路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询