在學(xué)習(xí)TCP/IP網(wǎng)絡(luò)的時(shí)候,我們會(huì)看到很多協(xié)議,比如TCP、ICMP、IP、HTTP等等,研究過這些協(xié)議的同學(xué)一定看到過如下的圖:



這些協(xié)議都是干嘛用的呢,為什么要規(guī)定這些協(xié)議呢,這也就引出了我們今天的話題 — 自定義協(xié)議。
我們以TCP協(xié)議建立的長連接為例來講,TCP協(xié)議是以流的方式進(jìn)行傳輸?shù)?,也就是它不?huì)關(guān)注是否接收到一個(gè)完整的數(shù)據(jù),或者是否多接收了其他數(shù)據(jù),只要讀取緩存有數(shù)據(jù)它就會(huì)一直讀取,也就到導(dǎo)致我們不知道數(shù)據(jù)是否完整或者接收了不相關(guān)數(shù)據(jù),所以我們需要一個(gè)規(guī)則來劃分不同的數(shù)據(jù),這就是我們要自定義的協(xié)議。
目前主要有兩種方式來定義協(xié)議,一種是規(guī)定好頭部長度,然后頭部中標(biāo)識數(shù)據(jù)長度,接收端根據(jù)協(xié)議頭部數(shù)值,選擇接收多少數(shù)據(jù),例如TCP、IP等;另一種是類似HTTP協(xié)議方式,規(guī)定頭部以"\r\n\r\n"結(jié)束,頭部每行以"\r\n"結(jié)束,然后頭部會(huì)指定Content-Length(當(dāng)然還有chunked的方式,這不在討論范圍),接收端也是根據(jù)頭部指定大小來讀取body(當(dāng)然也可以指定0)。
我們知道在Android推送服務(wù)中有MQTT和XMPP協(xié)議,我們?yōu)榱搜菔菊麄€(gè)流程,也為了其他長連接服務(wù)提供幫助,這里我們選擇自定義一個(gè)協(xié)議:

這里分別解釋一下各個(gè)字段的用處:
- Version:指定協(xié)議的版本號,因?yàn)閰f(xié)議可能會(huì)變更,但要兼容老的版本,比如HTTP1.0/1.1/2.0。
- Head Hength:頭部長度,接收端根據(jù)該字段分割head和body。
- Agreement:協(xié)議(也可以叫命令),不同的協(xié)議對應(yīng)不同的處理方式,比如推送給客戶端需要一種處理方式,心跳檢測需要一種處理方式,push serv和Conn serv需要一種處理方式,這里公用一種結(jié)構(gòu)。
- Extend:我們的協(xié)議經(jīng)常會(huì)出現(xiàn)不完善的情況,所以我們經(jīng)常會(huì)預(yù)留部分?jǐn)?shù)據(jù)備用。
- Content Length:Body大小,接收端根據(jù)此字段判斷Body終止。
- Syn:發(fā)送標(biāo)識符,用于標(biāo)識本次請求唯一性(參考TCP協(xié)議,在push服務(wù)中很少用到)。
- Ack:確認(rèn)標(biāo)識符,對應(yīng)Syn標(biāo)識符,Ack = Syn + 1(參考TCP協(xié)議)
到此我們?yōu)閜ush服務(wù)自定義協(xié)議完成,當(dāng)然這個(gè)協(xié)議不是死的,需要根據(jù)具體業(yè)務(wù)進(jìn)行設(shè)計(jì),為了設(shè)計(jì)更好的協(xié)議,可以參考一些比較成熟的協(xié)議規(guī)范。
下一章,我們該講如何保證高可用了……