一旦客戶端和服務器建立了Socket通信連接,接下來粘包和拆包就是一個必須要考慮的問題
本文是關(guān)于使用TCP協(xié)議下Socket粘包和拆包的處理思路
一個大前提:TCP協(xié)議是可靠的,數(shù)據(jù)包一定會到達(99.9%的情況下),而且是按順序到達,所以就不需要考慮UDP協(xié)議丟包和亂序的問題
一個小前提:TCP協(xié)議會根據(jù)數(shù)據(jù)包的大小和網(wǎng)絡通訊狀況對數(shù)據(jù)包合并發(fā)送或分片(分包),一個重要的嘗試就是大于MTU值的數(shù)據(jù)包一定會被分割震庭,因此當數(shù)據(jù)包到達時會出現(xiàn)兩種情況:1、和其他數(shù)據(jù)包的一部分或者整體連成一個大包你雌,2:被分割成幾個小包先后到達
因此器联,為了確定每個包的起始位置,需要在要發(fā)送的數(shù)據(jù)前面加上包頭匪蝙,包頭里一般記錄了數(shù)據(jù)的長度,復雜一點了要加上壓縮標志位和CRC校驗位等信息习贫,以便于檢錯逛球。更嚴格的情況下還會加上包尾
首先從緩沖流中讀取一個包頭的長度(假設是4個字節(jié)),如果連一個包頭都讀不出來,要么是連接中斷了(處理異常苫昌,檢查心跳颤绕,進入超時等待),要么是網(wǎng)絡有延遲需要繼續(xù)接收
解析包頭數(shù)據(jù)祟身,得到包體長度
進入讀取循環(huán)
判斷緩沖流中剩余的數(shù)據(jù)長度是否大于包體長度
大于等于(粘包的情況)奥务,則讀取一個包體,然后將緩沖流清空袜硫,將剩余數(shù)據(jù)寫回緩沖流(其實就是改變流指針的位置) 然后繼續(xù)讀取下一個包頭
小于(被拆分了)氯葬,則跳出讀取循環(huán),繼續(xù)等待下一次數(shù)據(jù)接收(可以是異步等待)
對于連接斷開婉陷,可以分為服務器知道客戶端斷開(客戶端主動用四次揮手和服務器斷開)帚称,和不知道客戶端斷開(拔網(wǎng)線),前一種情況走正常流程就可以了秽澳,后一種情況下有時鏈路層會通知網(wǎng)絡層闯睹,進而拋出異常,比如16001担神,處理之楼吃。可靠的做法還是使用心跳檢測,設定在若干秒后沒有收到心跳包,就由服務器主動結(jié)束這個連接