首先講了進程和線程區別
然后講解 管道和套接字,它是進程間通信的方式
接著講解共享變量 ,它是線程間通信
最后講解TCP三次握手,因為套接字使用了TCP協議
一、線程和進程的區別
線程(Thread)和進程(Process)是操作系統中并發執行的兩個基本單位。它們都可以執行任務,但作用范圍和資源管理方式不同。
🧩 一張對比表快速理解
比較項 | 進程(Process) | 線程(Thread) |
---|---|---|
基本定義 | 系統資源分配的最小單位 | CPU調度的最小單位(屬于進程) |
是否獨立 | 相互獨立,擁有各自內存空間 | 同一進程下線程共享內存空間 |
資源占用 | 占用資源較多(獨立地址空間) | 占用資源少(共享進程資源) |
通信方式 | 進程間通信(IPC)復雜(如管道、socket) | 線程間通信簡單(共享變量) |
創建銷毀代價 | 創建和銷毀開銷大 | 開銷相對小 |
崩潰影響 | 一個進程崩潰不會影響其他進程 | 一個線程崩潰可能影響整個進程 |
舉例 | Chrome每個標簽頁一個進程 | Chrome標簽頁中的多個腳本線程 |
🔧 舉個例子說明
想象你開了一家餐廳:
-
一個進程就像一個餐廳,彼此獨立。
-
一個線程就像餐廳里的服務員(共享廚房、菜單、收銀臺)。
你開的多個餐廳之間(進程)是互不影響的,但一個餐廳中的多個服務員(線程)可以一起服務,但他們共享資源,配合更緊密。
📦 編程角度理解
-
在 Java、Python、Node.js 中,我們可以通過
thread
,child_process
,worker_threads
創建線程或進程。
Node.js 中示例
// 創建子進程
const { fork } = require('child_process');
fork('child.js');// 創建線程(Node.js 10+)
const { Worker } = require('worker_threads');
new Worker('./worker.js');
📌 總結記憶口訣
“進程是房子,線程是房間”
一個進程里可以有多個線程,但線程不能脫離進程單獨存在。
如果你在學 Node.js、Java 或 Python 并發模型,我可以分別幫你分析線程/進程的用法和適用場景。需要我進一步展開哪門語言下的實踐案例?
二、進程間通信中管道是什么
在操作系統中,管道(Pipe)是一種常見的進程間通信(IPC, Inter-Process Communication)機制,允許一個進程把數據發送給另一個進程,就像水流通過水管一樣。
🧱 一句話解釋
管道就是一個連接兩個進程的通信通道,一個進程寫入數據,另一個進程讀取數據。
🧠 管道的原理
-
管道本質上是一個內核緩沖區(FIFO 隊列)。
-
寫端寫入數據 → 內核緩沖 → 讀端讀取數據。
-
是半雙工通信(數據只能單向流動)。
📦 管道的類型
類型 | 說明 |
---|---|
匿名管道 | 父子進程間通信(只能在具有親緣關系的進程間使用) |
命名管道 FIFO | 允許無親緣關系的進程通信,有名稱(文件路徑),位于文件系統中 |
🔧 舉例(Node.js)
匿名管道(spawn 使用標準輸入輸出)
const { spawn } = require('child_process');const child = spawn('node', ['-e', `process.stdin.pipe(process.stdout)`]);child.stdin.write('Hello from parent!\n');
child.stdin.end();
child.stdout.on('data', data => {console.log(`Child says: ${data}`);
});
命名管道(Linux Bash 示例)
# 創建命名管道
mkfifo mypipe# 一個終端:向管道寫入
echo "Hello" > mypipe# 另一個終端:從管道讀取
cat < mypipe
🚦 特點和限制
-
? 進程間數據共享,快速。
-
? 管道通信不需要借助中間文件。
-
? 匿名管道只能用于父子進程。
-
? 半雙工通信(除非建立兩個管道)。
-
? 不能跨網絡使用(僅限本地進程)。
? 常見應用場景
-
Shell 中的命令管道(
ls | grep txt
) -
父子進程間傳遞數據(如 Node.js 中子進程通信)
-
輕量級、無鎖通信場景
💬 總結口訣
匿名管道親緣深,命名管道通陌生;寫端數據流向讀,半雙工最常見。
如果你想知道在 Java、C/C++、Python 中怎么實現管道通信,也可以舉例說明。是否需要我給出跨語言的管道實現?
三、進程間通信socket是什么
在操作系統中,Socket(套接字)是最強大、最靈活的進程間通信(IPC)機制之一,它不僅能實現本地通信,還能支持網絡通信(跨主機)。
🧠 一句話解釋
Socket 就是一種通信端點,用于兩個進程之間發送和接收數據,無論這兩個進程是在同一臺機器上,還是在不同主機上。
🏗? 工作原理
Socket 通信的基本模型是 客戶端-服務器(Client-Server)模型:
-
服務器進程監聽某個地址(IP + 端口)。
-
客戶端進程主動連接這個地址。
-
雙方建立連接后就可以雙向通信(全雙工)。
📦 套接字類型(按通信范圍)
類型 | 范圍 | 示例說明 |
---|---|---|
本地套接字 | 同一臺機器上通信 | Unix Domain Socket (文件路徑) |
網絡套接字 | 跨主機通信 | TCP/IP、UDP 套接字 |
🔧 Node.js 中的 Socket 通信示例
1. 本地通信(UNIX Socket)
// server.js
const net = require('net');
const server = net.createServer((socket) => {socket.on('data', (data) => {console.log('Server received:', data.toString());});
});
server.listen('/tmp/mysocket'); // 本地 socket 文件
// client.js
const net = require('net');
const client = net.createConnection('/tmp/mysocket', () => {client.write('Hello from client');
});
2. 網絡通信(TCP Socket)
// tcp-server.js
const net = require('net');
const server = net.createServer((socket) => {console.log('Client connected');socket.on('data', (data) => {console.log('Server received:', data.toString());socket.write('pong');});
});
server.listen(3000);
// tcp-client.js
const net = require('net');
const client = net.createConnection(3000, 'localhost', () => {client.write('ping');
});
client.on('data', (data) => {console.log('Client received:', data.toString());
});
🚦 特點
特性 | 描述 |
---|---|
📡 通用性強 | 本地通信、遠程通信都可用 |
🔁 全雙工 | 可以雙向同時讀寫 |
📁 文件描述符 | 在類 UNIX 系統中 Socket 是一種特殊的文件描述符 |
🔐 可配加密 | 可以集成 TLS/SSL 實現安全通信(HTTPS、WSS 等) |
🧱 適合復雜通信 | 比如多客戶端并發、長連接、大數據傳輸等 |
🆚 與其他通信方式對比
通信方式 | 是否跨主機 | 是否雙向 | 應用難度 | 性能 | 常見用途 |
---|---|---|---|---|---|
管道 pipe | ? 本地 | 🚫 半雙工 | 簡單 | 高 | 父子進程簡單數據傳輸 |
消息隊列 | ? 本地 | ? | 中 | 中 | 多進程異步通信 |
Socket | ? 本地+遠程 | ? 全雙工 | ? 復雜 | 中-高 | 服務端、網絡通信 |
共享內存 | ? 本地 | ? | 復雜 | ? 極快 | 高性能數據交換 |
🧪 Socket 常用場景
-
本地服務與客戶端通信(如數據庫客戶端)
-
網絡服務(Web Server、Chat Server)
-
微服務間通信(配合 TCP/HTTP)
-
實時推送(WebSocket)
? 總結口訣
Socket 是個洞,進程互打通。可遠程可本地,網絡通信最通用。
如果你想繼續了解:
-
UDP socket
和TCP socket
區別 -
WebSocket
和原始socket
的差異 -
socket.io
使用實例(前后端實時通信)
可以告訴我,我可以一并講清楚。
四、TCP三次握手
我們從原理到實戰場景全面講清楚 TCP 三次握手(Three-way Handshake),并且深入探討你提到的重點問題:“是否可以省略第三次握手?”
🔍 一、什么是 TCP 三次握手?
三次握手是建立 TCP 連接時客戶端和服務器之間必須進行的 三步通信流程,確保雙方都具備發送和接收能力,才能正式開始數據傳輸。
🧠 二、三次握手詳解(圖 + 文)
lua
復制編輯
客戶端 服務端 | ------ SYN -------> | (第一次握手:客戶端發起請求) | <----- SYN-ACK -----| (第二次握手:服務端確認并回應) | ------ ACK ------->| (第三次握手:客戶端確認)
? 第一次握手(客戶端 → 服務端)
-
客戶端發送一個帶
SYN
標志的數據包。 -
表示:“我要連接你,并且我能發送數據了。”
-
此時客戶端進入
SYN_SENT
狀態。
? 第二次握手(服務端 → 客戶端)
-
服務端收到
SYN
后,確認客戶端能發送。 -
回復一個帶
SYN+ACK
標志的包。 -
表示:“我知道你要來,我也可以發送數據。”
-
服務端進入
SYN_RECEIVED
狀態。
? 第三次握手(客戶端 → 服務端)
-
客戶端收到
SYN+ACK
后,再發一個ACK
。 -
表示:“我知道你也準備好了,我們開始吧!”
-
此時雙方進入
ESTABLISHED
狀態,連接建立成功。
📌 三次握手的目的總結
目的 | 舉例 |
---|---|
? 確保客戶端能發送 | 第一次握手 |
? 確保服務端能接收并能發送 | 第二次握手 |
? 確保客戶端能接收 | 第三次握手 |
?是否可以省略第三次握手?
不能省略。
原因:
-
如果省略,服務端無法確認客戶端“收到了”自己的 SYN+ACK。
-
網絡不穩定或中間設備重發,可能導致服務端誤以為連接成功,出現半連接(SYN Flood 漏洞)。
-
TCP 協議設計就是為了防止這種“單向認為建立連接”的問題。
🧪 示例場景:省略第三次握手會怎么樣?
-
客戶端發了 SYN,服務端發了 SYN+ACK,但客戶端沒有發 ACK 就宕機了。
-
如果不等待第三次握手:
-
服務端誤以為連接建立。
-
客戶端其實已經沒了。
-
服務端一直占用連接資源,白白浪費(資源泄漏)。
-
🧱 補充:SYN Flood 攻擊
攻擊者連續偽造 IP 發送 SYN 包,但不發送第三次 ACK。
-
服務端進入
SYN_RECEIVED
,等待 ACK 卻等不到,連接被掛起。 -
持續攻擊會讓服務端連接數爆滿,無法為正常用戶服務。
解決方案:
-
使用 SYN Cookie 技術。
-
連接隊列限制。
? 總結口訣
三次握手不多余,確認彼此都OK。缺一不可防欺騙,少了連接不安全。
如果你還想進一步了解:
-
四次揮手斷開連接機制
-
TCP 狀態轉換圖(如
TIME_WAIT
,CLOSE_WAIT
) -
和 HTTP 的握手區別(如 HTTP/1.1 vs HTTP/2)
我可以繼續為你展開。
五、子進程和主進程區別和API
在 Node.js 中,子進程(child process)用于執行一個獨立的任務或運行另一個程序,與主進程并行執行、互不干擾。這是 Node 在單線程模型中實現多任務處理(并發/并行)的常用手段。
🧠 一、主進程 vs 子進程 的區別
對比項 | 主進程 | 子進程 |
---|---|---|
啟動方式 | node 直接啟動 | 主進程通過 child_process 模塊創建 |
內存空間 | 獨立進程,擁有自己的內存空間 | 也是獨立的,和主進程不共享內存(需顯式通信) |
執行上下文 | 當前運行的 Node.js 文件和上下文 | 可運行任意 Node.js 文件或外部命令 |
是否共享事件循環 | ? 不共享事件循環 | 每個子進程有自己的事件循環 |
通信方式 | - | 通過 IPC(進程間通信)或標準輸入輸出 |
錯誤影響 | 主進程出錯影響全局 | 子進程崩潰不影響主進程,反之亦然 |
🚀 二、創建子進程的 4 個核心 API(child_process
模塊)
你需要通過:
const child_process = require('child_process');
進行調用。
1?? exec(command[, options], callback)
-
用于執行一個命令行命令,適合處理結果較小的任務。
-
會將子進程的輸出(stdout 和 stderr)緩存在內存中,傳給回調函數。
const { exec } = require('child_process');exec('ls -la', (err, stdout, stderr) => {if (err) {console.error('錯誤:', err);return;}console.log('標準輸出:', stdout);
});
2?? execFile(file[, args][, options][, callback])
-
直接執行一個可執行文件(比如
.exe
,.sh
,.py
),不會通過 shell 解析。 -
安全性更高、性能更好,適用于直接調用程序文件。
const { execFile } = require('child_process');execFile('node', ['--version'], (err, stdout) => {if (err) throw err;console.log('Node 版本是:', stdout);
});
3?? spawn(command[, args][, options])
-
更底層,適合**處理大數據流(持續輸出)**的子進程。
-
返回一個 ChildProcess 對象,你可以用
stdout.on('data')
來獲取數據。
const { spawn } = require('child_process');const child = spawn('ping', ['baidu.com']);child.stdout.on('data', (data) => {console.log(`輸出:${data}`);
});child.stderr.on('data', (data) => {console.error(`錯誤:${data}`);
});child.on('close', (code) => {console.log(`子進程退出碼:${code}`);
});
4?? fork(modulePath[, args][, options])
? 專為 Node.js 腳本間的多進程通信而設計,默認通過 IPC 通信(
process.send()
和message
事件)。
// parent.js
const { fork } = require('child_process');
const child = fork('./child.js');child.send({ msg: 'Hello from parent!' });child.on('message', (msg) => {console.log('父進程接收:', msg);
});
// child.js
process.on('message', (msg) => {console.log('子進程接收:', msg);process.send({ reply: 'Got it!' });
});
? 三、適用場景對比總結
API | 適合場景 | 是否支持通信 | 是否緩沖輸出 |
---|---|---|---|
exec | 簡單命令 + 小輸出結果 | ? | ?(內存緩存) |
execFile | 運行本地程序、腳本 | ? | ? |
spawn | 處理持續輸出(如視頻轉碼) | ? | ?(流式處理) |
fork | Node 之間多進程通信 | ? | ? |
🔧 四、如何終止子進程?
使用:
child.kill(); // 默認發送 SIGTERM 信號
📦 五、補充推薦閱讀
-
官方文檔:https://nodejs.org/api/child_process.html
-
Node.js進程模型分析文章
-
Node.js高級編程書籍中的“多進程架構”
需要我結合實戰:比如用子進程處理圖片壓縮、日志分析、CPU 密集計算等例子嗎?或者再帶你寫一個完整的 fork 通信項目也可以。