欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Netty中最簡單的粘包解析方法分享

 更新時(shí)間:2023年05月16日 14:55:52   作者:寧軒  
黏包 是指網(wǎng)絡(luò)上有多條數(shù)據(jù)發(fā)送給服務(wù)端, 但是由于某種原因這些數(shù)據(jù)在被接受的時(shí)候進(jìn)行了重新組合,本文分享了一種最簡單的黏包解析方法, 非常適用于初初初級(jí)選手

前言

黏包 是指網(wǎng)絡(luò)上有多條數(shù)據(jù)發(fā)送給服務(wù)端, 但是由于某種原因這些數(shù)據(jù)在被接受的時(shí)候進(jìn)行了重新組合, 這就是黏包, 本篇文章用來演示一種最簡單的黏包解析方法, 適用于初初初級(jí)選手

正常來講客戶端發(fā)送給服務(wù)端的消息, 都是存在專門的通訊協(xié)議的, 為了避免黏包現(xiàn)象, 我們通常有幾種方式去制定相應(yīng)的規(guī)則: 消息長度固定, 特定分隔符, 消息長度固定+特定分隔符

本文是采用了 特定分隔符 的方式, 每條數(shù)據(jù)包都以 \n 結(jié)尾

例如以下三條原始數(shù)據(jù)數(shù)據(jù):

hell\n
ningxuan\n
thanks\n

變成了以下兩個(gè):

hello\nningxuan\nth
anks\n

這就是黏包

黏包產(chǎn)生的原因

socket 網(wǎng)絡(luò)編程中, TCPUDP 分別是面向連接和非面相連接的. 但是他們都存在產(chǎn)生黏包問題嗎?

本文不會(huì)對 tcp 和 udp 進(jìn)行詳細(xì)的講解, 感興趣的可以自行百度或者掘金

tcp

先說結(jié)論: tcp 會(huì)產(chǎn)生黏包問題

由于 tcp 協(xié)議本身的機(jī)制(面向連接的可靠性協(xié)議-三次握手機(jī)制) 客戶端與服務(wù)端會(huì)維持一個(gè)連接(Channel), 數(shù)據(jù)在連接不斷開的情況下, 可以將多個(gè)數(shù)據(jù)包持續(xù)不斷的發(fā)送到服務(wù)器上.

但是如果發(fā)送的網(wǎng)絡(luò)數(shù)據(jù)包太小, tcp就會(huì)啟用Nagle算法對多個(gè)數(shù)據(jù)包進(jìn)行合并再發(fā)送到服務(wù)器上. 這種情況下服務(wù)器在接收到消息的時(shí)候無法區(qū)分哪些數(shù)據(jù)包是分開的, 所以產(chǎn)生了黏包

還有一種可能是: 服務(wù)器在接收到數(shù)據(jù)之后, 將數(shù)據(jù)放入到緩沖區(qū)中, 如果消息沒有被及時(shí)的從緩沖區(qū)取走, 下次在取數(shù)據(jù)的時(shí)候就會(huì)出現(xiàn)一次取到多個(gè)數(shù)據(jù)包的情況, 造成黏包現(xiàn)象

tcp三次握手:

  • 客戶端服務(wù)端發(fā)送建立通道請求
  • 服務(wù)端客戶端發(fā)送允許客戶端建立一個(gè)單向的數(shù)據(jù)通道; 服務(wù)端向客戶端發(fā)送建立通道請求
  • 客戶端服務(wù)端發(fā)送允許服務(wù)端建立一個(gè)單向的數(shù)據(jù)通道

此時(shí)數(shù)據(jù)通道是雙向的, 允許客戶端、服務(wù)端互相發(fā)送消息

Nagle算法:

  • 如果包長度達(dá)到 MSS, 則允許發(fā)送
  • 如果該包中含有 FIN, 則允許發(fā)送
  • 設(shè)置了 TCP_NODELAY 選項(xiàng), 若所有發(fā)出去的小數(shù)據(jù)包(長度小于 MSS )均被確認(rèn), 則允許發(fā)送
  • 若上述條件均未滿足, 但發(fā)送了超時(shí)(一般為 200ms ), 則立即發(fā)送

udp

upd 不存在黏包問題

udp本身是無連接的不可靠傳輸協(xié)議, 不會(huì)對數(shù)據(jù)包進(jìn)行合并發(fā)送, 也就沒有Nagle算法, 不會(huì)存在數(shù)據(jù)合并的情況, 每一個(gè)數(shù)據(jù)包都是完整的, 所以不存在黏包現(xiàn)象

最簡單的黏包解析

黏包解析也很簡單:

  • 遍歷當(dāng)前的 ByteBuffer 緩沖區(qū)
  • 判斷元素為 '\n' 的下標(biāo)
  • 生成新的 ByteBuffer 緩沖區(qū)
  • 將起始下標(biāo)到標(biāo)記下標(biāo)的字符寫到新的緩沖區(qū)

具體代碼如下所示:

public class ByteBufferTest {
    public static void main(String[] args) {
        ByteBuffer buffer = ByteBuffer.allocate(32);
        buffer.put("hello\nningxuan\nth".getBytes());
        split(buffer);
        buffer.put("anks\n".getBytes());
        split(buffer);
    }

    private static void split(ByteBuffer buffer){
        // 將 buffer 切換為 讀模式
        buffer.flip();
        // 根據(jù) buffer 當(dāng)前的長度進(jìn)行遍歷
        for (int i = 0; i < buffer.limit(); i++) {
            // 判斷當(dāng)前下標(biāo)元素是不是數(shù)據(jù)包切割符 \n
            if (buffer.get(i) == '\n'){ // 注意這個(gè)時(shí)候 buffer 的 position 屬性一直為 0
                // 計(jì)算當(dāng)前數(shù)據(jù)包長度
                int length = i + 1 - buffer.position();
                // 根據(jù)當(dāng)前數(shù)據(jù)包長度, 動(dòng)態(tài)生成新的 緩沖區(qū)
                ByteBuffer target = ByteBuffer.allocate(length);
                for (int j = 0; j < length; j++) {
                    target.put(buffer.get());   // 注意這個(gè)時(shí)候 buffer 的 position 屬性在 ++
                }
                // 打印 target 當(dāng)前的元素和屬性
                ByteBufferUtils.selectAll(target);
            }
        }
        buffer.compact();
    }
}

到此這篇關(guān)于Netty中最簡單的粘包解析方法分享的文章就介紹到這了,更多相關(guān)粘包解析內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論