- 互聯(lián)網(wǎng)應(yīng)用中各個(gè)組成部分的協(xié)作方式
- 客戶端與服務(wù)端通信方式
- 服務(wù)器之間通信方式
- 工程實(shí)踐中的問題和解決方案
服務(wù)器S和客戶端C僅僅是角色

CS通信
CS的連接方式是使用socket建立連接來進(jìn)行數(shù)據(jù)交互,數(shù)據(jù)交互的過程分為:
- Server創(chuàng)建socket,監(jiān)聽(listen)特定端口(ip+port)
- Client創(chuàng)建socket,連接到Server監(jiān)聽的端口
- Server接收Client連接,創(chuàng)建socket與之進(jìn)行通信
- Client和Server進(jìn)行數(shù)據(jù)交互
- Client和Server斷開連接回收資源

傳輸協(xié)議
- UDP 可靠性要求不高、小數(shù)據(jù)量、性能更佳
- TCP 可靠、適合大數(shù)據(jù)量、頻繁交互的
案例分析
PC上QQ的CS交互
- 一般情況下 UDP
- 網(wǎng)絡(luò)情況差 TCP
- 拉去圖片等大文件 TCP
手機(jī)上微信的CS交互(有錢了)
- 前臺(tái)運(yùn)行時(shí):TCP長連接
- 后臺(tái)運(yùn)行時(shí):TCP短鏈接
- 查看文章等:HTTP(TCP短鏈接)
應(yīng)用層協(xié)議
- 從傳輸層拿到的原始數(shù)據(jù),應(yīng)該如何使用?
- 字符串
- 自定義
- protobuf
- 序列化和反序列化

UDP的分包
假設(shè)每個(gè)分片丟包概率為10%,每個(gè)數(shù)據(jù)包有3次重發(fā)的邏輯。 如果發(fā)送一個(gè)10K數(shù)據(jù)包,成功的概率是多少呢?如果發(fā)送10個(gè)1K的數(shù)據(jù)包,全部成功的概率是多少呢?
UDP的分片MTU為1480,由于還包含8字節(jié)的包頭,實(shí)際上應(yīng)該是1472。
10K的數(shù)據(jù)可以劃分為7個(gè)分片,單次成功概率為90%^7=47.8%。 再經(jīng)過3次重發(fā)修正,最終成功概率為(1-47.8%)^3=86%。
10個(gè)1K的數(shù)據(jù)包相當(dāng)于10個(gè)分片,單包成功概率(1-10%)^3=99.9%。 最終全部成功的概率為99.9%^10=99.9%。
雖然成功的概率相差不大,但是失敗的概率卻相差了14倍。 另外UDP中不要讓單個(gè)包的數(shù)據(jù)量超過1K。
設(shè)計(jì)CS交互時(shí)的問題
case1: 客戶端收到的數(shù)值總是跟服務(wù)器對(duì)不上
可能是字節(jié)序問題,有的不同CPU在不同的OS上字節(jié)序可能不同, 可通過字節(jié)序轉(zhuǎn)換來解決。
在將數(shù)據(jù)發(fā)送到網(wǎng)絡(luò)前,會(huì)對(duì)數(shù)據(jù)包做一次字節(jié)序轉(zhuǎn)換,轉(zhuǎn)換成網(wǎng)絡(luò)字節(jié)序,網(wǎng)絡(luò)字節(jié)序是一個(gè)BIG ENDING的。
case2: 服務(wù)器下發(fā)的小包數(shù)據(jù),客戶端常常延遲一段時(shí)間才收到。
服務(wù)器下發(fā)的小包數(shù)據(jù) 客戶端常常會(huì)延遲一段時(shí)間才收到,一般會(huì)延遲200ms。網(wǎng)絡(luò)良好時(shí)發(fā)送大包時(shí)經(jīng)常隔個(gè)十幾毫秒就收到了。原因是nagle算法延遲導(dǎo)致小包延遲發(fā)送,nagle算法是小包不是立即發(fā)送而是先緩存起來,等其他包過來時(shí)再一起發(fā)送,或者等超時(shí)才發(fā)送。 在一些延遲比較敏感的應(yīng)用中, 可以禁用nagle算法。
case3: 實(shí)時(shí)交互中數(shù)據(jù)量較大或網(wǎng)絡(luò)波動(dòng)較大時(shí)容易發(fā)送失敗
實(shí)時(shí)交互中數(shù)據(jù)量較大或網(wǎng)絡(luò)抖動(dòng)比較厲害, 例如平常單個(gè)玩家在地圖上跑來跑去或打個(gè)怪什么的,這時(shí)數(shù)據(jù)量是很小的。但如果幾百個(gè)玩家聚集在一起,每個(gè)人動(dòng)一下或喊一聲話,那數(shù)據(jù)量會(huì)瞬間變得非常大, 此時(shí)發(fā)送的數(shù)據(jù)超過接收容量, 導(dǎo)致發(fā)送的緩沖區(qū)爆滿,傳輸速度變慢。此時(shí)會(huì)導(dǎo)致客戶端斷掉等各種問題,解決的方案是適當(dāng)?shù)匕l(fā)送緩沖加大一點(diǎn)兒。注意的是適當(dāng)?shù)丶哟?,一般是1M或2M左右。
要點(diǎn)
為什么要使用非阻塞的IO呢?為什么要把socket設(shè)計(jì)成non-blocking呢。因?yàn)橐粋€(gè)服務(wù)器是為好多個(gè)客戶當(dāng)一起去服務(wù)的,如果使用阻塞IO的話,客戶端發(fā)送一個(gè)數(shù)據(jù)過來,那么數(shù)據(jù)庫就會(huì)直接卡在那里了。如果在客戶端沒有上行的數(shù)據(jù)的時(shí)候, 服務(wù)器一直處于等待狀態(tài),后續(xù)操作無法進(jìn)行。而非阻塞IO是如果receive沒有的話服務(wù)器會(huì)馬上返回。
多路復(fù)用主要是檢測(cè)文件與描述符的狀態(tài)變化, 用于提高運(yùn)行效率。不用針對(duì)每個(gè)描述符 ,例如很多個(gè)socket,不用去一個(gè)個(gè)去檢查。 而是可以采取各種方式
(select、poll、epoll)找出里面那些有狀態(tài)變化了,有數(shù)據(jù)來了或者可以繼續(xù)給它追加數(shù)據(jù)了。
服務(wù)器上的通信方式

從客戶端client這邊來說,它看到的可能就只有一個(gè)接入服務(wù)器,它并不知道后面有一個(gè)很龐大的服務(wù)器組。
在簡(jiǎn)化的游戲服務(wù)器架構(gòu)中,有一個(gè)連接服務(wù)器、一個(gè)世界服務(wù)器以及很多個(gè)scene,以及其他的logicsvr等。這些服務(wù)器之間有什么特點(diǎn)呢?有的服務(wù)器是在同一個(gè)物理機(jī)上的,也有可能在不同物理機(jī)上 ,所以它們的交互方式會(huì)更為多樣一點(diǎn)兒。
服務(wù)器之間SS的連接方式
- TCP:最為常用
- UDP:非關(guān)鍵數(shù)據(jù)上報(bào)(如在線)、日志服務(wù)
- 非socket通信
進(jìn)程間通信除了socket之外還有管道pipe、signal、shm、message queue、file。
UDP協(xié)議使用時(shí)數(shù)據(jù)包不要定太大一般不要超過1K,而在進(jìn)程間通信一般在內(nèi)網(wǎng)環(huán)境中,是可以超過這個(gè)MTU設(shè)定值的。這樣的話,不用在協(xié)議層去做分包邏輯。UDP本身包的最大限制是64KB,還需要剪掉一個(gè)IP包頭,再減去一個(gè)UDP包頭,減下來也就不到64KB了。
用戶登錄老是登錄不上,或者登陸上去后,玩一下就會(huì)斷掉,會(huì)是什么原因呢?
- 最有可能是網(wǎng)路狀況不佳
- 連接錯(cuò)了接入服務(wù)器
國內(nèi)的網(wǎng)絡(luò)環(huán)境比較特殊,存在多個(gè)網(wǎng)絡(luò)運(yùn)營商,而且運(yùn)營商之間的交互式比較差的,有可能是一個(gè)電信的用戶連入了聯(lián)通的一個(gè)接入點(diǎn),就會(huì)出現(xiàn)經(jīng)常卡頓或斷線等各種問題。 - 服務(wù)器的網(wǎng)路故障
如網(wǎng)卡燒掉了或網(wǎng)線弄斷了 - 數(shù)據(jù)同步量太大
- 服務(wù)器卡頓