feat: comprehensive documentation and demo updates

- Update READMEs and docs across multiple languages
- Enhance interactive demos for Agent, LLM, VLM, Audio, Image Gen, Terminal, and Web Basics
- Add new appendix sections for Database and IDE intros
- Update VitePress config, theme, and utility scripts
- Clean up unused assets and components
This commit is contained in:
sanbuphy
2026-01-16 19:10:21 +08:00
parent c8567ce23f
commit 73f4788d7e
150 changed files with 19530 additions and 13401 deletions
@@ -1,122 +1,70 @@
<template>
<div class="tcp-handshake-demo">
<div class="participants">
<div class="participant client">
<div class="participant-icon">💻</div>
<div class="participant-name">客户端</div>
<div class="participant-ip">192.168.1.100</div>
<div class="diagram">
<!-- Client Column -->
<div class="column client">
<div class="actor-icon">💻 Client</div>
<div class="state-label">{{ clientState }}</div>
</div>
<div class="connection-area">
<div class="connection-line" :class="{ active: step >= 1 }"></div>
<div class="packets">
<div
v-for="(packet, index) in packets"
:key="index"
class="packet"
:class="{
active: step === index + 1,
sent: step > index + 1
}"
<!-- Interaction Area -->
<div class="interaction-zone">
<!-- Step 1: SYN -->
<div class="packet-row" :class="{ active: step === 1, done: step > 1 }">
<button
@click="sendSyn"
:disabled="step !== 0"
class="packet-btn syn"
>
<div class="packet-content">{{ packet.content }}</div>
<div class="packet-direction">{{ packet.direction }}</div>
</div>
SYN (SEQ=x)
</button>
</div>
<!-- Step 2: SYN-ACK -->
<div
class="packet-row reverse"
:class="{ active: step === 2, done: step > 2 }"
>
<button
@click="sendSynAck"
:disabled="step !== 1"
class="packet-btn syn-ack"
>
SYN-ACK (ACK=x+1, SEQ=y)
</button>
</div>
<!-- Step 3: ACK -->
<div class="packet-row" :class="{ active: step === 3, done: step > 3 }">
<button
@click="sendAck"
:disabled="step !== 2"
class="packet-btn ack"
>
ACK (ACK=y+1)
</button>
</div>
</div>
<div class="participant server">
<div class="participant-icon">🖥</div>
<div class="participant-name">服务器</div>
<div class="participant-ip">93.184.216.34</div>
<!-- Server Column -->
<div class="column server">
<div class="actor-icon">🖥 Server</div>
<div class="state-label">{{ serverState }}</div>
</div>
</div>
<div class="controls">
<button
class="control-btn"
@click="startHandshake"
:disabled="handshaking || step === 3"
>
{{ step === 3 ? '✅ 握手完成' : handshaking ? '🔄 握手中...' : '🤝 开始三次握手' }}
</button>
<button class="control-btn reset" @click="reset" v-if="step === 3">
🔄 重新演示
</button>
<div class="status-message">
<p v-if="step === 0">点击 <strong>SYN</strong> 开始连接</p>
<p v-if="step === 1">
服务器收到了请求现在需要回复 <strong>SYN-ACK</strong>
</p>
<p v-if="step === 2">
客户端收到了确认最后发送 <strong>ACK</strong> 完成握手
</p>
<p v-if="step === 3" class="success">🎉 连接已建立 (ESTABLISHED)!</p>
</div>
<div class="step-explanation">
<div class="explanation-title">当前步骤说明</div>
<div class="explanation-content" v-if="step === 0">
点击"开始三次握手"按钮观察客户端和服务器如何建立可靠连接
</div>
<div class="explanation-content" v-else-if="step === 1">
<strong>第一步SYN同步请求</strong>
<br><br>
客户端发送一个 SYN 包给服务器告诉服务器"我想和你建立连接"
<br>
客户端会生成一个随机序列号seq=x这个号码很重要后续的数据传输都要用它来保证数据不丢失不重复
</div>
<div class="explanation-content" v-else-if="step === 2">
<strong>第二步SYN-ACK同步确认</strong>
<br><br>
服务器收到客户端的 SYN 请求后
<br>1. 生成自己的随机序列号seq=y
<br>2. 把客户端的序列号加 1ack=x+1表示"我收到了你的请求"
<br>3. 发送 SYN-ACK 包给客户端
</div>
<div class="explanation-content" v-else-if="step === 3">
<strong>第三步ACK确认</strong>
<br><br>
客户端收到服务器的 SYN-ACK
<br>1. 把服务器的序列号加 1ack=y+1表示"我也收到了你的确认"
<br>2. 发送 ACK 包给服务器
<br><br>
<strong>🎉 连接建立成功</strong>双方现在可以开始传输数据了
</div>
</div>
<div class="why-three">
<div class="why-title">🤔 为什么需要三次握手</div>
<div class="why-content">
<div class="why-item">
<strong>1. 确认双方都能正常收发数据</strong>
<br>
第一次握手证明客户端能发送
<br>
第二次握手证明服务器能接收和发送
<br>
第三次握手证明客户端能接收
</div>
<div class="why-item">
<strong>2. 防止已失效的连接请求突然传到服务器</strong>
<br>
如果只有两次握手客户端发送的第一个连接请求在网络中滞留
等到连接释放后才到达服务器服务器会误以为是新的连接请求
浪费资源三次握手可以避免这个问题
</div>
<div class="why-item">
<strong>3. 同步双方的初始序列号</strong>
<br>
双方需要协商一个起始序列号用于后续的数据传输和确认
</div>
</div>
</div>
<div class="analogy">
<div class="analogy-title">💡 生活中的类比</div>
<div class="analogy-content">
想象你在打电话给朋友
<br><br>
<strong></strong>"喂?你能听到我说话吗?" SYN
<br>
<strong>朋友</strong>"能听到,你能听到我吗?" SYN-ACK
<br>
<strong></strong>"我也能听到!" ACK
<br><br>
现在双方确认都能听到对方可以开始正常通话了
</div>
</div>
<button v-if="step === 3" @click="reset" class="reset-btn">Reset</button>
</div>
</template>
@@ -124,44 +72,29 @@
import { ref } from 'vue'
const step = ref(0)
const handshaking = ref(false)
const clientState = ref('CLOSED')
const serverState = ref('LISTEN')
const packets = [
{
content: 'SYN seq=x',
direction: '客户端 → 服务器'
},
{
content: 'SYN-ACK seq=y, ack=x+1',
direction: '服务器 → 客户端'
},
{
content: 'ACK ack=y+1',
direction: '客户端 → 服务器'
}
]
const sendSyn = () => {
step.value = 1
clientState.value = 'SYN_SENT'
}
const startHandshake = () => {
if (handshaking.value || step.value === 3) return
const sendSynAck = () => {
step.value = 2
serverState.value = 'SYN_RCVD'
}
handshaking.value = true
step.value = 0
setTimeout(() => {
step.value = 1
setTimeout(() => {
step.value = 2
setTimeout(() => {
step.value = 3
handshaking.value = false
}, 1500)
}, 1500)
}, 500)
const sendAck = () => {
step.value = 3
clientState.value = 'ESTABLISHED'
serverState.value = 'ESTABLISHED'
}
const reset = () => {
step.value = 0
handshaking.value = false
clientState.value = 'CLOSED'
serverState.value = 'LISTEN'
}
</script>
@@ -169,219 +102,127 @@ const reset = () => {
.tcp-handshake-demo {
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 20px;
background: var(--vp-c-bg-soft);
margin: 20px 0;
background-color: var(--vp-c-bg-soft);
padding: 1.5rem;
margin: 1rem 0;
font-family: var(--vp-font-family-mono);
text-align: center;
}
.participants {
.diagram {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30px;
gap: 20px;
margin-bottom: 2rem;
}
.participant {
flex: 1;
text-align: center;
padding: 20px;
background: var(--vp-c-bg);
border-radius: 8px;
border: 2px solid var(--vp-c-divider);
}
.participant.client {
border-color: #3b82f6;
}
.participant.server {
border-color: #ef4444;
}
.participant-icon {
font-size: 3rem;
margin-bottom: 10px;
}
.participant-name {
font-size: 1rem;
font-weight: bold;
color: var(--vp-c-text-1);
margin-bottom: 5px;
}
.participant-ip {
font-size: 0.8rem;
color: var(--vp-c-text-3);
font-family: monospace;
}
.connection-area {
flex: 1;
position: relative;
padding: 20px;
}
.connection-line {
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 2px;
background: var(--vp-c-divider);
transition: all 0.3s;
}
.connection-line.active {
background: linear-gradient(90deg, #3b82f6, #ef4444);
}
.packets {
.column {
width: 120px;
display: flex;
flex-direction: column;
gap: 15px;
position: relative;
z-index: 1;
gap: 1rem;
}
.packet {
padding: 12px;
.actor-icon {
font-size: 1.2rem;
font-weight: bold;
}
.state-label {
padding: 0.5rem;
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 6px;
border: 1px solid var(--vp-c-divider);
border-radius: 4px;
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
.interaction-zone {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
gap: 1.5rem;
padding: 0 2rem;
}
.packet-row {
display: flex;
justify-content: flex-start;
opacity: 0.3;
transform: scale(0.9);
transition: all 0.3s;
}
.packet.active {
.packet-row.reverse {
justify-content: flex-end;
}
.packet-row.active {
opacity: 1;
transform: scale(1.05);
border-color: var(--vp-c-brand);
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
}
.packet.sent {
opacity: 0.6;
.packet-row.done {
opacity: 1;
}
.packet-content {
font-size: 0.85rem;
color: var(--vp-c-brand);
font-family: monospace;
font-weight: 600;
margin-bottom: 4px;
}
.packet-direction {
font-size: 0.75rem;
color: var(--vp-c-text-3);
}
.controls {
display: flex;
gap: 10px;
margin-bottom: 25px;
justify-content: center;
}
.control-btn {
padding: 12px 24px;
background: var(--vp-c-brand);
color: white;
.packet-btn {
padding: 0.5rem 1rem;
border-radius: 20px;
border: none;
border-radius: 6px;
font-size: 0.9rem;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
}
.control-btn:hover:not(:disabled) {
background: var(--vp-c-brand-dark);
}
.control-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.control-btn.reset {
background: #22c55e;
}
.control-btn.reset:hover {
background: #16a34a;
}
.step-explanation {
background: var(--vp-c-bg);
border-radius: 8px;
padding: 20px;
margin-bottom: 25px;
border-left: 4px solid var(--vp-c-brand);
}
.explanation-title {
font-size: 1rem;
font-weight: bold;
color: var(--vp-c-text-1);
margin-bottom: 12px;
}
.explanation-content {
font-size: 0.9rem;
color: var(--vp-c-text-2);
line-height: 1.8;
}
.why-three {
background: var(--vp-c-bg);
border-radius: 8px;
padding: 20px;
margin-bottom: 25px;
}
.why-title {
font-size: 1rem;
font-weight: bold;
color: var(--vp-c-text-1);
margin-bottom: 15px;
}
.why-content {
display: flex;
flex-direction: column;
gap: 15px;
}
.why-item {
font-family: monospace;
font-size: 0.85rem;
color: var(--vp-c-text-2);
line-height: 1.8;
padding: 12px;
background: var(--vp-c-bg-soft);
border-radius: 6px;
transition: all 0.2s;
background: var(--vp-c-bg-alt);
border: 1px solid var(--vp-c-divider);
}
.analogy {
background: var(--vp-c-bg);
border-radius: 8px;
padding: 20px;
border-left: 4px solid #f59e0b;
.packet-btn:not(:disabled):hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.analogy-title {
font-size: 1rem;
font-weight: bold;
color: var(--vp-c-text-1);
margin-bottom: 12px;
.packet-btn.syn {
background: #3b82f6;
color: white;
}
.packet-btn.syn-ack {
background: #f59e0b;
color: white;
}
.packet-btn.ack {
background: #10b981;
color: white;
}
.analogy-content {
.packet-btn:disabled {
background: var(--vp-c-bg-alt);
color: var(--vp-c-text-3);
cursor: not-allowed;
border-color: transparent;
}
.status-message {
height: 2rem;
margin-bottom: 1rem;
font-size: 0.9rem;
color: var(--vp-c-text-2);
line-height: 1.8;
}
.status-message .success {
color: #10b981;
font-weight: bold;
}
.reset-btn {
padding: 0.5rem 1.5rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 4px;
cursor: pointer;
}
.reset-btn:hover {
background: var(--vp-c-bg-alt);
}
</style>