转载请注明文章出处:https://tlanyan.me/many-http-…
今天打开任务管理器,发现有大量“HTTP Auto Proxy Detection Worker Process”进程,画风如下:
<img src=”https://tlanyan.me/wp-content…; alt=”” width=”1002″ height=”890″ class=”aligncenter size-full wp-image-3215″ />
根据进程名称,应该和代理有关,因为电脑上开着 Shadowsocks。但是这么多什么鬼?打群架吗?
退出 SS 程序,发现这些进程不会随之退出。意识到这超出了我的知识范围,于是马上打开 Google 学学。根据有限的搜索结果,基本上确认和 SS 有关,并且仅会出现在 1809 版的 Windows 10 上。我今天才发现这个现象,顺便确认了系统是 1809 版的 bug10:
<img src=”https://tlanyan.me/wp-content…; alt=”” width=”690″ height=”619″ class=”aligncenter size-full wp-image-3216″ />
花了一个多小时理解 WPAD、PAC 和 pacjsworker.exe 关系,并加上自己反复测验,得到一些结论:
HTTP Auto Proxy Detection Worker Process 进程的程序文件是 ”C:WindowsSystem32pacjsworker.exe”,由 WPAD 服务启动;
这些进程不能手工杀死,重启系统才能解决,用户退出 (logout) 再登录也不行;
WPAD 服务(Win HTTP Web Proxy Auto Discovery Service)的属性不能修改,通过重启 WPAD 服务杀死进程的路也不通;
1809 版本才会出现,在这之前版本的系统上运行正常;根据 Twitter 链接 https://twitter.com/epakskape…
情况复现:打开 SS 客户端,选择 PAC 模式,勾选启用系统代理;然后按电源键(或其他方式)让电脑进入休眠;接着唤醒电脑进入桌面,任务管理器中就多了一个 HTTP Auto Proxy Detection Worker Process 进程;如此反复进入休眠又启动,每次都会出现一个新进程;
后来发现不需要休眠也能复现情况:打开 SS 客户端,选择 PAC 模式,打开任务管理器;然后不断禁用 / 启用系统代理,在任务管理器窗口中可实时看到每次启用系统代理后都会多一个进程;
最新版的 SS 客户端依然有这个问题;
每次 SS 启动系统代理后的 PAC 地址均不同;
PAC 地址中的 secret 参数仅在勾选“保护本地 PAC(secure local PAC)”选项时才会出现,但 t 参数一直都在。
根据网上知识,加上个人实验和思考,对问题原因的理解为:WPAD 是系统关键服务,用户不能更改;以 PAC 模式启动 SS 时,SS 会在 LAN 配置中设置一个新的 PAC 脚本地址;WPAD 检测到有新的 PAC 脚本地址,唤醒一个新的 pacjsworker.exe 进程监听该地址;PAC 地址失效后,监听进程不退出,于是进程堆积,慢慢出现几十上百个进程的壮观场景。
总结问题根源:1. Windows 10 的进程不自动退出;2. 每次从休眠过来后,SS 客户端生成不同的 PAC 地址并将其配置到 LAN 设置中。
把问题搞清楚了,解决方案基本上章口就莱:
使用全局模式;全局模式不会设置 PAC 配置脚本,WPAD 服务也就不会拉起新的进程;
等待巨硬修复问题;去年下半年就爆出问题,到现在问题依旧,应该有得等(本人最近才更新 1809 版本,故而发现得迟);另外我不认为这是巨硬的锅,他们未必会修复;
重新编译 SS 客户端,生成相同的 PAC(至少未重启 SS 客户端前 PAC 地址应一致)。
我的解决方案是重新编译 SS 客户端,根据 @Joelism 的提示及自己理解,做了两个方案的客户端:
方案一:总是生成相同的 PAC 地址,除非人工编辑 ”pac-secret.txt” 文件。改动代码如下:<pre>// 文件:shadowsocks-csharpControllerServicePACServer.cs
public void UpdateConfiguration(Configuration config){this._config = config;
if (config.secureLocalPac){// 注释掉部分 // var rd = new byte[32];// RNG.GetBytes(rd);// PacSecret = $”&secret={Convert.ToBase64String(rd)}”;if (!File.Exists(PAC_SECRET_FILE)){var rd = new byte[32]; RNG.GetBytes(rd); string secret = Convert.ToBase64String(rd); PacSecret = $”secret={secret}”; File.WriteAllText(PAC_SECRET_FILE, secret);}else{PacSecret = $”secret={File.ReadAllText(PAC_SECRET_FILE)}”;}}else{PacSecret = “”;}// 注释掉部分 // PacUrl = $”http://127.0.0.1:{config.localPort}/pac?t={GetTimestamp(DateTime.Now)}{PacSecret}”;PacUrl = $”http://127.0.0.1:{config.localPort}/pac?{PacSecret}”;}</pre>
这个方案保证不管系统休眠重启,还是退出 SS 客户端再打开,都只会有一个 HTTP Auto Proxy Detection Worker Process 进程。
仅当系统中无 PAC 进程运行时才生成新的 PAC 地址并设置到 LAN 中。代码如下:<
pre>// 文件:shadowsocks-csharpControllerShadowsocksController.cs
protected void Reload(){Encryption.RNG.Reload();// some logic in configuration updated the config when saving, we need to read it again_config = Configuration.Load();StatisticsConfiguration = StatisticsStrategyConfiguration.Load();
if (privoxyRunner == null) {privoxyRunner = new PrivoxyRunner(); } if (_pacServer == null) {_pacServer = new PACServer(); _pacServer.PACFileChanged += pacServer_PACFileChanged; _pacServer.UserRuleFileChanged += pacServer_UserRuleFileChanged; // 这一行代码从外部移入 _pacServer.UpdateConfiguration(_config); } // 每次唤醒都更新的代码删除 // _pacServer.UpdateConfiguration(_config); if (gfwListUpdater == null) {gfwListUpdater = new GFWListUpdater(); gfwListUpdater.UpdateCompleted += pacServer_PACUpdateCompleted; gfwListUpdater.Error += pacServer_PACUpdateError; }
这个方案保证不退出 SS 客户端情况下只有一个 pacjsworker.exe 进程。缺点是如果频繁退出并重启 SS 客户端,同样会出现有大量进程的现象。
根据源代码思路,我认为第二种方案更合理,是原作者想要的。当然你应该想得到,我是先根据网上提示实现方案一,测试达到效果后继续思考才做出的方案二。从这个角度也是方案二更合理。
两个方案的 exe 文件我都编译好了,需要请自取:方案一 方案二
稍后我会发一个 pull request 到官方库,使用方案二修复该问题。
问题相关网页
https://github.com/shadowsock…
https://github.com/XX-net/XX-…
https://github.com/shadowsock…
https://github.com/shadowsock…
https://steamcn.com/t430331-1-1
http://bbs.pcbeta.com/forum.p…