端口占用问题后续
https://blog.wangzhy.com/blog/windows-port-occupancy-issue 后续
发现是因为开启了 Clash Verge 的 tun 模式。
tun 模式的工作原理
- 创建虚拟网卡,所有的流量都会被重定向到这个虚拟网卡
- 接管所有的网络
- 系统级代理
- 本地回环地址
- 进程间的本地通信
- 端口绑定冲突,Clash 为了转发流量可能会做一下操作
- 预先占用或监听某些端口
- 拦截端口绑定操作
- DNS 劫持和流量重定向
- 防火墙级别拦截
https://blog.wangzhy.com/blog/windows-port-occupancy-issue 后续
发现是因为开启了 Clash Verge 的 tun 模式。
tun 模式的工作原理
是否每天都觉得过筋疲力尽,这大概归因于两点。
然后你就需要用意志力(willpower)去克服阻力(resistance),获得干活的动力(motivation),久而久之就产生了倦怠(burnout)。
willpower -> resistance -> motivation ..... burnout
为了解决这个现象,需要搞明白三个问题。
第一个问题:阻力来自哪里?
每天都有很多事要做,但是直到一天都快过完了,任务却没有完成多少,觉得自己今天啥都没干又浑浑噩噩的过了一天,躺在床上,思考今天本应该要完成的事。大脑突然充满干劲,但你现在什么都干不了(总不能起来吧,你明天还有很多事要做呢,还得上班呢)然后,你失眠了。第二天,又重复这个过程,形成一个恶性循环。
第二个问题:如何应付阻力?
养成一个好习惯(habit),因为习惯是 autopilot 的(理解为本能),你只用花费很少的意志力就能克服阻力。
养成一个好习惯需要经历 4 个阶段。决策(decision),启动(initiation),强化(reinforcement),养成习惯(habit)。
decision: 做一个决策是很容易的,比如想要干一件事,想要学习什么东西。做这个决定是很容易的,几乎不需要克服什么阻力(也许是强加给你的,比如上级安排的任务)。
initiation: 启动的阻力和门槛也很低。开始干活/学习,制定一个计划也没有什么难度。
reinforcement: 强化这个阶段就需要克服极大的阻力了,需要重复,直到养成一个好习惯。
habit: 这是我们的终极目标。
将强化阶段根据认为心理学划分为四个象限,横轴是 reinforcement 和 punishment,纵轴是 positive 和 negative。
正向强化就是通过增加某些东西(如多巴胺)来强化系统。一般是通过奖励机制来获得多巴胺,但这个会随着时间的推移,逐渐适应(3-6周)。它虽然有效,但难以维持。
负向强化通过移除某些负面行为来强化习惯。比如强烈的警告(未系安全带时的紧迫提示音,快到 DDL 的工作任务)等。通过解决这些东西来进行强化习惯(这不是一个好习惯)。 这个短期有效,不能持续。因为这个是依赖压力或者某些 bad things. 通过解决压力或 bad things 来进行强化。所以有的人就会把所有的事堆在一起,等到 DDL 的时候 才会开始处理。然后得到了一种强化,然后下次还这样。于是一个坏的习惯就养成了。但是对现在并没有任何改变。每天还是会有很多事情等着你。一个好的负向强化方案是:当你 感觉到压力大的时候,尝试冥想,这会使你放松,压力减小,使你得到了一种强化。
正向惩罚,就是通过增加一些不好的东西使你得到惩罚(低效且不可靠)。因为正向惩罚只教你不应该做什么,而没有教你应该怎么做。正向惩罚会导致负强化增强,这是一个恶性循环。 只有在一些情况下,正向惩罚是有效的/推荐的。那就是在危机人身安全的时候。
负向惩罚,通过移除某些东西来进行惩罚。如不准玩游戏,不准出门。
还有一个概念就是 extinction(灭绝)。extinction 指的是通过移除维持行为的强化物来避免某种行为。某种不好的行为存在是因为有某种强化物导致它存在,你要做的就是移除这种强化物。
拖延症就是一种负向强化。
解决拖延症一个好的方案是,给一个 3-5 分钟的时间,不以完成任务为目的开始做这件事,到时间之后你可以选择是否要继续。持续这样,知道养成习惯。
另一个好的方法是,准备好干这件事需要的东西,如你要学习什么东西,那就提前一天把文档打开,工具打开,第二天直接干就好了。 坐下来好好想想,要从现状到完成目标,需要完成哪些步骤,不应该做什么。保持以解决问题为导向,思考 what can i do.把能提前做的都提前做。
想想所有阻碍你前进的障碍,what can i do。
你应该寻找解决方案,而非仅发现问题。
今天碰到了一个很诡异的端口占用问题。
项目使用的端口是 9052,在启动的时候出现了下面的提示。
Description:
Web server failed to start. Port 9052 was already in use.
Action:
Identify and stop the process that's listening on port 9052 or configure this application to listen on another port.
这是一个很常见的端口占用问题,通过下面的命令就能解决了。
netstat -aon | findstr "9052"
taskkill /T /F /PID 1234
但是,在我执行 netstat -aon | findstr "9052" 之后,什么都没有输出。
奇了怪了,不应该呀。然后用 TCPView 搜索 9052 端口占用情况,也什么都没有输出。
然后我把我的问题丢给了 AI。
netstat -ano | findstr 9052 查找不到占用 9052 的应用程序,但是在启动 springboot 的时候,出现了以下提示,我应该如何排查问题? 找出占用 9052 的应用程序?
Description:
Web server failed to start. Port 9052 was already in use.
Action:
Identify and stop the process that's listening on port 9052 or configure this application to listen on another port.
AI 给了我一些的建议
用管理员运行 cmd,然后再主席 netstat 命令
使用 TCPView 软件查看
检查是否是被 IPv6 占用
netstat -ano -p tcp | findstr 9052
netstat -ano -p tcpv6 | findstr 9052
使用 PowerShell 执行下面的命令 (好使)
Get-NetTCPConnection -LocalPort 9052 | Format-Table -Property LocalAddress, LocalPort, State, OwningProcess
# 然后查看进程详情
Get-Process -Id <PID>
得到下面的输出
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
2865 686 227392 34016 204.83 16184 1 Foxmail
最后查出来是 FoxMail 占用了 9052 端口。
那现在的问题是为什么 netstat 没有结果输出, Get-NetTCPConnection -LocalPort 9052 却可以找到占用 9052 端口的应用呢?
我继续向 AI 追问。
为什么 netstat -ano | findstr 9052 没有结果输出,而 Get-NetTCPConnection -LocalPort 9052 | Format-Table -Property LocalAddress, LocalPort, State, OwningProcess 却可以找出占用 9052 端口的应用?
AI 的解释是 2 个命令的工作原理不一样。
netstat 比较老,是从 TCP/IP 协议栈的缓存中读取数据,数据不是实时的,有刷新延迟。在某些情况下,短连接或者刚建立的连接可能不会立即显示。
Get-NetTCPConnection 直接查询内核, 更准确及时。
还有一个问题,Tcpview.exe 也是从内核中读取数据,为什么当时我也没有找到呢?
继续向 AI 追问
那为什么 Tcpview.exe 没有读取到数据,Get-NetTCPConnection -LocalPort 9052 | Format-Table -Property LocalAddress, LocalPort, State, OwningProcess 却读到了数据?
AI 给出了几个可能的原因:

9052,但是 TCPView 的显示可能是 *:9052. 我应该输入 :9052但是现在这个问题已无法复现了,无法得知具体是哪一个原因。只能等到后续这个问题再次出现才能知道原因了。
那么,如果这个问题再次出现,我应该如何执行什么命令,来确定它的根本问题?
继续就这个问题向 AI 追问。
由于 netstat -ano | findstr 9052 和 TCPView 查询不出数据,Get-NetTCPConnection -LocalPort 9052 | Format-Table -Property LocalAddress, LocalPort, State, OwningProcess 却可以找出占用 9052 端口的应用的问题已无法复现,那么下次这个问题再次出现,我应该执行什么命令来确定这个问题的根本原因?
AI 给我返回了一个 .ps1 文件,是的,一个 .ps1 文件,之前我从来没有接触过 ps1 的任何语法。
我粗略的看了下这个 .ps1 文件,用到的语法大概是定义变量/方法,执行方法,搭配一些 if-else 语句。
然后我给 AI 提问,让它给我介绍下这些语法。
我之前从来没接触过 ps1 脚本请向我解释 ps1 中如何定义变量,方法,如何执行方法,if-else 语 句的语法。
.ps1 语法学习时间
变量
$name = value 来定义变量
$arr = @("apple","banana","orange") 定义数组
定义哈希表
$person = @{
Name = "wangzhy"
Age = 29
City = "zhuhai"
}
定义布尔值
$isActive = $true
$isDeleted = $false
特殊变量
$_$?$null$true$false$HOME$PSVersionTable变量的使用
"my name is $name" => my name is wangzhy'my name is $name' => my name is $name函数
function name {
# function body
}
在函数体内通过 param($name) 获取参入的参数。默认按照参数传递顺序进行赋值,也可以指定。
function add {
param($a,$b)
Write-Host "a = $a"
Write-Host "b = $b"
return $a + $b
}
Write-Host " a + b = " (add 2 10) # a=2,b=10
Write-Host " a + b = " (add -b 2 -a 10) # a=10,b=2
给函数参数设置默认值 param($a,$b = 11) 如果没有给 b 传递值,那么 b 的默认值是 11。
条件判断
if(conditon){
} elseif(conditon) {
} else {
}
比较运算符
-eq
-ne
-gt
-ge
-lt
-le
-eq
-ceq 忽略大小写
-like 模糊匹配
-math 正则匹配
-and
-or
-not
三元运算符 $result = ($age -ge 18) ? "成年" : "未成年"
$() 的用途
$($process.Id) 执行 $process 对象的 Id 属性$($a + $b)Write-Host "当前时间: $(Get-Date -Format 'HH:mm:ss')"$($connection[0].LocalPort).ps1 脚本文件的格式要是 **UTF-8 with BOM** 的,不然的话,如果包含中文,会出现报错。
管道符 | 的使用:将左边命令的输出传递给右边命令的输入。
Get-Process | Sort-Object CPU -Descending | Select-Object -First 5 获取进程 → 排序 → 选择前 5 个123 | Set-Clipboard 将 123 输出到剪贴板最后得到一个 .ps1 文件
# ============================================
# 指定端口(通过 -port 传入,默认是 9052 端口)占用问题诊断脚本
# 当问题出现时立即运行此脚本
# ============================================
param($port = 9052)
$timestamp = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
$logFile = "port_diagnosis_$timestamp.txt" # 日志文件
function Run-Write-Log {
param($Command)
$CommandResult = iex $Command
$Message = $CommandResult
if ($Message -isnot [string]) {
$Message = $Message | Out-String
}
Write-Host "========== $Command ==========" -ForegroundColor "GREEN"
Write-Host $Message
"========== $Command ==========" | Out-File -FilePath $logFile -Append -Encoding UTF8
$Message | Out-File -FilePath $logFile -Append -Encoding UTF8
return $CommandResult
}
$ignore = Run-Write-Log "netstat -ano | findstr :$port"
$cr = Run-Write-Log "Get-NetTCPConnection -LocalPort $port -ErrorAction SilentlyContinue"
if ($null -ne $cr) {
# 这里要对 $($conn.OwningProcess) 去重
foreach ($conn in ($cr | Select-Object -Property OwningProcess -Unique)) {
$ignore = Run-Write-Log "Get-Process -Id $($conn.OwningProcess)"
}
}
# 通过 vscode 打开这个日志文件
code $logFile
原文: https://www.chrisgregori.dev/opinion/code-is-cheap-now-software-isnt
code is cheap now, software isn't
构建软件的门槛已经坍塌,任何人都可以通过 Claude Code 成功构建出一个程序。
这个程序只是为了解决一个一次性问题的,用之即弃。就像 txt 文本,临时记录一些内容。
软件真正的成本不在于初始编写,而在于后续维护、边界情况处理、不断累计的 UX debt(用户体验债务)以及数据所有权的复杂性。
软件工程正在迈入新时代。
https://x.com/dotey/status/2010852013874045284
AI 编程正在从代码补全进化到自主执行开发任务的 AI 智能体。
软件开发的工作岗位可能跟会变少或变多。 变少是因为 AI 编程导致了一个人 + AI 能够干的活相当于之前的一个团队。 变多是因为 AI 编程让软件开发进入到之前从未雇佣程序员的领域(如成本或者技术问题)。
所以,未来需要的是一个精通 AI 的多面手。“你 + AI” 要能抵得过之前的一个团队。
初级程序员应该具备的技能:
高级程序员应该具备的技能:
28 原则。 AI 编程中,80% 的工作 AI 能处理的很好,20% 的工作是机器搞不定的。如架构、棘手的集成、创造性设计、边缘情况等。
编程方式在转变:少打样板代码(重复代码),多审查逻辑错误、安全缺陷和需求偏差(做出来的东西与需求不一致)。 关键技能变成了软件架构、系统设计、性能调优和安全分析。
初级开发者应该:
高级程序员应该:
未来,编写代码的主力一定是会变成 AI。 程序员会编程代码的审计员(程序员变成清洁工,清理 AI 生成的垃圾)或扩展为设计和治理 AI 系统的核心编排者(人人都是架构师,指挥 AI Agents 协同工作)。
初级开发者应该:
高级程序员应该:
在技术栈快速变化、AI 渗透的环境下,T 型工程师更吃香:既有广泛的适应力,又有一两手绝活。
AI 工具其实是通才的神器。 后端工程师可以用 AI 做个像样的 UI;前端专家可以用 AI 生成服务端代码。 AI 让人的能力边界大幅拓展。 反观深度专才,领地被自动化蚕食,却难以突围。
初级开发者应该:
高级程序员应该:
初级开发者应该:
高级程序员应该:
无论未来是迎来编程复兴,还是代码自我编写的世界,永远需要这样一种工程师:思考全面、持续学习、用技术解决真问题。
别把 AI 当拐杖,要把它当陪 练。 即使有计算器,你也得先懂数学原理。
-- 禁用外键检查
SET FOREIGN_KEY_CHECKS = 0;
TRUNCATE TABLE ACT_EVT_LOG;
TRUNCATE TABLE ACT_GE_BYTEARRAY;
TRUNCATE TABLE ACT_HI_DETAIL;
TRUNCATE TABLE ACT_HI_COMMENT;
TRUNCATE TABLE ACT_HI_IDENTITYLINK;
TRUNCATE TABLE ACT_HI_PROCINST;
TRUNCATE TABLE ACT_HI_VARINST;
TRUNCATE TABLE ACT_HI_TASKINST;
TRUNCATE TABLE ACT_HI_ACTINST;
TRUNCATE TABLE ACT_RU_IDENTITYLINK;
TRUNCATE TABLE ACT_RU_TASK;
TRUNCATE TABLE ACT_RU_VARIABLE;
TRUNCATE TABLE ACT_RU_EXECUTION;
TRUNCATE TABLE ACT_HI_ATTACHMENT;
TRUNCATE TABLE ACT_RU_EVENT_SUBSCR;
TRUNCATE TABLE ACT_RU_JOB;
TRUNCATE TABLE ACT_PROCDEF_INFO;
TRUNCATE TABLE ACT_RE_DEPLOYMENT;
TRUNCATE TABLE ACT_RE_MODEL;
TRUNCATE TABLE ACT_RE_PROCDEF;
SET FOREIGN_KEY_CHECKS = 1;
元素选择器 querySelector('div')
ID 选择器 querySelector('#id')
类选择器 querySelector('.myClass')
属性选择器
querySelector('[data-id]') 有 data-id 属性querySelector('[type="text"]') type 属性值为 textquerySelector('[href^="https"]') href 以 https 开头querySelector('[class*="btn"]') class 包含 btn后代选择器 querySelector('div a')
直接子元素选择器 querySelector('div > a')
相邻兄弟选择器 querySelector('h1 + p') h1 之后相邻的 p 元素
伪类选择器
:first-child 第一个子元素:last-child:nth-child(n) 第 n 个子元素:nth-last-child(n):first-of-type 第一个相同类型的子元素:last-of-type:nth-of-type(n):only-child 唯一的子元素:only-of-type:hover:focus:active:checked:disabled:enabled:visited 已访问的链接:not(selector)复 杂组合的案例
// 选择 class 为 container 的 div 中的所有选中的 checkbox
document.querySelectorAll('div.container input[type="checkbox"]:checked')
// 选择第一个 section 中的最后一个 p 标签
document.querySelector('section:first-of-type p: last-child')
// 选择不含 disabled 类的按钮
document.querySelectorAll('button:not(. disabled)')
// 选择所有偶数行的 tr
document.querySelectorAll('tr:nth-child(even)')
Terminal 就是一个由等大单元格组成的网格.
每个单元格只能存放一个字符加上一些样式(颜色,加粗,下划线).
转义序列(Escape Sequences): 特殊字符序列控制着 Terminal 的行为(移动光标, 改变颜色, 清空屏幕)
当你按一下个键时, 终端会向程序发送转义之后的字符序列. (终端默认不会发送鼠标事件。程序需要先请求鼠标追踪功能,之后点击操作才会转换为带坐标的转义序列)
Signals(信号量): Ctrl + C 组合键不会输入字符,而是会发送一个信号. 终端会拦截特殊的组合键, 并转化为操作系统层面的事件(信号量), 用于中断或控制程序运行.
ctrl + c 中断 Interrupt
ctrl + z 暂停程序 Suspend
ctrl + D 文件结束 End of file
普通按键会转换为字节流传输给程序,而信号键则被终端拦截并转换为操作系统级别的事件,用于中断或控制进程。
Raw vs Cooked Mode
The Round Trip: 每次按键都会通过终端栈传递给程序,随后输出结果又会回流到屏幕上显示。
1. keystore -> 2. encode -> 3. Shell -> 4. execute -> 5. output -> 5. render (repeat!)
构 建复杂终端用户界面 (Building Complex TUIs)
┌─┐│) 绘制可视化边框focused)SIGWINCH 信号. TUI 会通过 ioctl() 获取新尺寸,重新计算各个区域尺寸并刷新整个屏幕显示.终端有 2 套屏幕, 终端根据输入在这 2 套屏幕之间切换.
Terminal Icons, 就是特殊渲染的 Unicode 字符
状态管理
Text Selection & Cursor Positioning
终端术语表

常见问题
source ~/.zshrc 让 Shell 重新加载配置