nodejs socket接收粘包問(wèn)題

使用nodejs的net創(chuàng)建socket連接后,先后連著發(fā)送一個(gè)登錄包和心跳包,應(yīng)該先后分別接收到兩個(gè)返回值,但是在nodejs里卻只返回了一次,并且這兩個(gè)值粘在一起了。

而使用python代碼大部分情況沒(méi)有出現(xiàn)粘包現(xiàn)象,但小概率偶爾也粘

原因

python 的 recv() 是阻塞讀取,而 nodejs 的 'data' 是異步回調(diào)推送

python

data = sock.recv(1024)

阻塞調(diào)用:調(diào)用時(shí)線程停在那里,直到至少有 1 個(gè)字節(jié)到達(dá)就會(huì)返回(不足 1024 也一樣返回)。
當(dāng)你第一次 recv() 時(shí),如果內(nèi)核緩沖區(qū)里此刻只有第一段包,Python 會(huì)立即返回,不會(huì)等第二段到。
所以消息一定會(huì)被拆成多次 recv() 調(diào)用,每次拿到當(dāng)時(shí)緩沖里已有的部分 → 100% 分成多次 log(只要你的發(fā)送是分兩次 send 而不是一次性全發(fā)的)

nodejs

socket.on('data', chunk => { ... })

'data' 是流模式:數(shù)據(jù)到達(dá),event loop 把“當(dāng)時(shí)緩沖區(qū)的全部?jī)?nèi)容”一起推給你。
Node.js 這邊不會(huì)像 Python 的阻塞 recv() 那樣中途“提前返回”,它會(huì)等到 事件循環(huán) 從 OS 拿數(shù)據(jù)的時(shí)候,把 OS 緩沖里當(dāng)時(shí)已經(jīng)到的所有數(shù)據(jù)都讀出來(lái)(兩個(gè)包已經(jīng)全到),然后合成一個(gè) chunk 調(diào)給你。
這種模式下,如果兩個(gè)包到達(dá)時(shí)間非常接近(一般在同一 TCP 拍發(fā)回去),Node 很可能一次性全讀出來(lái) → 100% 粘包的現(xiàn)象。

總結(jié)

Python 另開(kāi)線程阻塞 recv = “專(zhuān)人盯著” → 直接喚醒,延遲極小。
Node 事件循環(huán) = “統(tǒng)一調(diào)度” → 可能稍微晚一點(diǎn)才 read,容易積累數(shù)據(jù)。
粘包不是 Node 獨(dú)有,是 TCP 的本質(zhì)特性。
Python 阻塞只是讓多條消息在應(yīng)用層“分開(kāi)到”的概率更高,但不能避免。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容