swoole項目開發思惟轉換 -- 粘包

swoole是用php快速開發高效的tcp/udp服務, 其中tcp是用的更多的一個場景,http雖然是基於tcp協議的,但和直接開發tcp服務仍是有明顯的區別的。php

TCP是數據流前端

tcp是數據流,這是一個基本的概念,這裏有兩個要點:web

  1. 數據沒有邊界編程

    你能夠理解爲水在一個水管裏的流動,咱們不知道哪段數據是一個咱們須要的完整數據數組

  2. 收發有緩衝區服務器

    好比:當水從一端流到了另外一端,咱們在收數據的時候,不可能每來一滴水就處理一次,這個緩衝區就至關於有了一個水桶,再接了必定的水以後內核再給數據交到用戶空間,這樣能夠大大提高性能。swoole

那這裏就有一個問題:因爲這個特性,內核沒法知道哪部分數據是你想要的,因此應用層拿到數據多是完整數據,也多是不完整或者一部分完整、一部分不完整(粘包),那麼怎樣能獲得想要的數據呢?
網絡

數據協議tcp

數據協議能夠理解爲一種約定,按照這個約定來處理收到的數據進而獲得想要的數據,這個過程就稱爲拆包,那問題又來了?性能

web開發爲何不用考慮粘包

由於web的http能夠理解爲一個公共的數據協議,在實現一個web服務器的時候,就必需按照這個協議來進行數據處理,這樣保證在應用層獲取到數據是完整的數據,http是典型的包頭+包體的這個一個約定格式,有那現幾個特色:

  1. 經過\r\n\r\n來區分包頭和包體

  2. 包頭經過\r\n來區分不一樣的數據組

看個示例:

GET / HTTP/1.1

Host: www.swoole.com

Connection: keep-alive

這是一個典型的請求頭,第一行約定了請求的方法(GET/POST/PUT/DELETE等)、請求地址、http協議版本, 從第二行開始,都是健:值的形式,反應到PHP裏,就是$_SERVER超全局變裏裏 HTTP_開頭的數據,因爲這是GET請求,全部沒有包體,若是是POST或者response響應,咱們能夠看到包體,包體的長度經過包頭裏的Content-Length參數來控制的

Swoole怎麼處理粘包

swoole考慮到在粘包是一個必需處理的過程,內置了兩種方案:

  1. 約定結束符

    這個相似於c裏面的字符串數組,約定了\0表示字符串結束,在swoole裏,能夠的setting數組中,開啓open_eof_check=true,並用package_eof來設置一個完整數據結尾字符。

    舉個例子:

    "open_eof_check"=>true

    "package_eof" = >'swooleend',


    這裏設置了package_eof = 'swooleend', 那client在每一個完整數據以後再拼上swooleend以後,再發送到swoole server,swoole server就能自動識別並拼出一個完整的包。這裏又隱含了兩個小問題?

    a)  若是我一次收到了多個完整包怎麼辦?

            那能夠開啓 open_eof_split=>true, 這樣在onReceive裏回調裏拿到的數據就是一個完整的包了,不然須要業務層裏自行explode('swooleend', $data)了,

    b)  要保證業務數據裏不能出現package_eof設置的字符,不然將致使數據錯誤了。


  2. 自定義包頭包體

    這種方式也很常見,特別是在二進制數據流中,原理是經過約定數據流的前幾個字節來表示一個完整的數據有多長,從第一個數據到達以後,先經過讀取固定的幾個字節,解出數據包的長度,而後按這個長度繼續取出後面的數據,依次循環。

    相關配置:

        'package_length_type'   => 'N',      //數據unpack方式,這裏N表示無符號32位大端長整型,更多定義能夠參考:http://php.net/manual/zh/function.pack.php

        'package_length_offset'=> 0,       //第N個字節是包長度的值

        'package_body_offset'   => 4,       //第幾個字節開始計算長度

        'package_max_length'    => 2000000,  //協議最大長度


    這個配置表示,前端4個字節是數據包長度,按照N的方式解析,最後一個配置表示數據包的最大長度,這個配置的目的是爲了控制內存。


    總結,粘包處理是不少新作服務器網絡編程最容易碰到的問題,特別是長期作web開發的同窗,基本沒有這個概念,因此經過這個思惟轉換,更深刻的瞭解http協議,進而瞭解tcp協議,對服務器網絡編程是很是有好處的。

    相關文章
    相關標籤/搜索