(一)Socket服務器整體架構概述
2010-10-28 16:50 by 田志良, 4613 visits, 收藏, 編輯Socket服務器主要用于提供高效、穩(wěn)定的數據處理、消息轉發(fā)等服務,它直接決定了前臺應用程序的性能。我們先從整體上認識一下Socket服務器,Socket服務器從架構上一般分為:網絡層、業(yè)務邏輯層、會話層、數據訪問層,如圖:

?。▓D1)
(一) 網絡層
網絡層主要用于偵聽socket連接、創(chuàng)建socket、接受消息、發(fā)送消息、關閉連接。作為socket通信服務器,網絡層的性能相當重要,所以我們在設計網絡層時,要著重在以下幾方面獲得突破:最大連接數、最大并發(fā)數、秒處理消息數。如何突破呢?下面我為大家介紹幾種網絡層常用到的一些技術和技巧(具體實現,我將在博文中逐一具體闡述):
1)Buffer管理
每一個SocketAsyncEventArgs對象(以下簡稱SAEA)在內存中都有其對應的緩存空間,如果不對這些緩存空間進行同一管理,當SAEA對象逐漸增多時,這些SAEA對象的緩存空間會越來越大,它們在系統(tǒng)內存中不是連續(xù)的,造成很多內存碎片,而且這些緩存不能重復利用,當創(chuàng)建、銷毀SAEA對象時,造成CPU很多額外消耗,影響服務器性能。面對這問題如何解決呢?用Buffer池管理!
2)雙工通信
Socket服務器提高通信效率是一個永恒的話題,提高通信效率有很多種方法,雙工通信就是其中之一。一個SAEA對象在同一時刻只能用來接收數據或發(fā)送數據,有人想,如果一個SAEA對象在同一時刻既能發(fā)送數據又能接受數據,那肯定會提高socket通信效率。恩,很有想法!可是你能讓你的頭在同一時刻既往左轉又往右轉嗎?答案是不行的,那如何實現雙工通信呢?既然一個SAEA對象在同一時刻只能做一件事,那我自定義DuplexSAEA對象,在該對象中封裝兩個SAEA,一個用于接受,一個用于發(fā)送,問題不就解決了嗎。
3)poolOfAcceptEventArgs
poolOfAcceptEventArgs是個什么東西?它不是個東西,是一個容器,一個容納AcceptSAEA對象的容器。給你兩個socket服務器,你能很快判別兩個服務器性能的優(yōu)異嗎?很簡單,你瞬間向一臺服務器打入5、6萬的連接,看看會不會都連上,如果都連上,說明這臺socket服務器的并發(fā)處理連接的能力還是不錯的。那如何提高socket服務器的并發(fā)連接能力呢?答案:poolOfAcceptEventArgs!
4)消息隊列調度器
消息隊列調度器主要分為兩種:接受消息隊列、發(fā)送消息隊列。為什么要用消息隊列呢?主要是提高socket服務器的吞吐量。首先我們定義一個隊列Queue,然后編寫N個調度器,不斷從隊列中調度消息,接受隊列調度器用于將消息拋至業(yè)務邏輯層處理,發(fā)送隊列調度器用于調用網絡層發(fā)送消息接口,向指定端口發(fā)送數據。
5)心跳掃描
有一個困惑:客戶端連接socket服務器,連接沒有斷開,但客戶端掛了,這樣這條連接在socket服務器中就成了釘子戶,落地生根不走了!一個釘子戶還可以忍受,千千萬萬個呢?那就崩潰了!怎樣解決這個問題呢?定時掃描每條連接,如果該條連接在超時時間內沒有IO響應,則關閉它。
6)粘包
服務器在接受消息包時,如果兩個數據包同時被你服務器收了怎么辦?你會把他當成一個數據包嗎?如果一個數據包斷了,分成兩次被你服務器收了,你會把他們拼接起來嗎?這些就是粘包了,怎么解決?正則表達式掃描!
7)多線程編程
Socket服務器的編程就是多線程編程,面對多線程,線程間怎樣同步、怎樣避免死鎖?多線程訪問公共資源如何處理,在下面的博文中,我將會為大家具體闡述。
(二) 業(yè)務邏輯層
網絡層將解包后的消息包拋至業(yè)務邏輯層,業(yè)務邏輯層收到消息包后,解析消息類型,然后轉入相應的處理流程處理。
網絡層應提供發(fā)送消息的接口供業(yè)務邏輯層調用,因為網絡層不會主動發(fā)送消息,發(fā)送消息的操作是由業(yè)務邏輯層來控制的,所以業(yè)務邏輯層應根據具體的業(yè)務應用,封裝不同功能的發(fā)送消息的方法。
(三) 會話層
會話層主要用于記錄在線用戶信息,該層隸屬于業(yè)務邏輯層。既然隸屬于業(yè)務邏輯層,那為什么還要獨立出來呢?這主要為以后分布式開發(fā)拓展用,試想,一臺服務器最大能支持多少人同時在線?中國有多少人?如果1億人同時在線,你一臺服務器能支持得了嗎?答案肯定是否定的,所以要分布式開發(fā)。分布式開發(fā)涉及到用戶信息同步的問題,所以會話層就要獨立出來了。
(四) 數據訪問層
數據庫執(zhí)行效率是整個socket服務器的瓶頸?為什么呢?舉個例子:假設我們的socket服務器的秒處理消息的條數為3000,每處理一條消息都會保存歷史記錄,那么,如果數據訪問層不想拖網絡層的后腿,那么他的執(zhí)行sql語句的效率也必須達到每秒3000!如果socket服務器和數據庫服務器部署在同一網段上,這個速度是沒有問題的,但如果數據庫服務器部署在外網呢?你的sql語句的執(zhí)行效率能達到那么高嗎?很困難!
再思考一個問題:如果網絡層執(zhí)行線程和數據庫執(zhí)行線程是同一個線程,那么網絡層的處理必須等待數據庫執(zhí)行完畢后,才能進行!如果數據庫執(zhí)行效率比較慢,那對整個socket服務器將是一個毀滅性的打擊。
那么怎樣將數據訪問層與網絡層分離,讓他們互不影響?如何提高數據庫執(zhí)行效率,讓網絡層的處理速度和數據訪問層的處理速度達到一個平衡?答案:連接池+sql調度器+主從數據庫。
Socket服務器的整體架構就為大家介紹到這里,下面我將會為大家具體闡述各個技術的實現。







#1樓 BenBen789 2010-10-28 17:02
分析幾乎涉及了Socket的方方面面,期待你的精彩后文。。。#2樓 何必 2010-10-28 17:14
很想好好學學socket 期待精彩后文#3樓 田戶名 2010-10-28 17:29
good#4樓 阿瑞|www.16hi.com 2010-10-28 17:47
飄過 關注一下#5樓 溫景良(Jason) 2010-10-28 18:00
最后那個才是我關心的#6樓 zhenjing 2010-10-28 20:21
到目前為止,從沒見過通用的服務器架構,總是因背景不同而不同#7樓 onlyfew 2010-10-28 20:44
拭目以待#8樓 hhshuai 2010-10-28 22:26
拭目以待#9樓 clound 2010-10-28 23:00
LZ 繼續(xù),哈哈#10樓 wufm 2010-10-29 09:25
期待#11樓 張磊(Rey) 2010-10-29 10:33
精彩,LZ繼續(xù)#12樓 詩雨流蘇飄 2010-10-29 11:34
good!不錯,頂!#13樓 ToBin 2010-10-29 12:30
灰常期待,不知道是不是.net底下的#14樓 Sylvester 2010-10-29 13:41
正好需要,贊一個。#15樓 liveshow021_jxb 2010-10-29 14:46
學習一記,一直想加強這方面的能力#16樓 愛在兩腿間 2010-10-31 17:59
期待你的分享#17樓 小羅 2010-11-11 10:24
樓主, 很期待你的博文. 個人愛好和工作都設計到這一塊.#18樓 大頭豬 2010-11-11 13:42
我剛剛開始學習有關socket通訊的技巧,非常期待樓主下一篇博文。呵呵,俺就天天關注啦#19樓 ToBin 2010-11-25 17:34
博主,你這文章出了很久了也沒出下面的文章,天天看RSS都沒有,實在等的蛋蛋疼了上來問問博主,啥時候能出下文啊。。。#20樓 qiuqingpo 2010-11-29 10:23
樓主.你把你的精彩講述出一本書吧.我第一個去買!期待下下...#21樓 ToBin 2010-11-29 18:01
文中提到"那我自定義DuplexSAEA對象,在該對象中封裝兩個SAEA,一個用于接受,一個用于發(fā)送,問題不就解決了嗎"有個問題,雖然用了兩個saea對象,但都是使用的一個socket連接啊,能同時即接受又發(fā)送嘛 ?
#22樓 sofakeer 2010-12-01 14:56
老大 期待你的這個系列。。。。。關注中。。
#23樓 sofakeer 2010-12-09 20:52
老大 啥時候 繼續(xù)寫?。?BR>期待死我了!我要。。。。???!
呵呵
#24樓 彭杰斌 2010-12-24 11:09
看到樓主的開篇,眼前一亮,期待后續(xù)大作。#25樓 o﹎Lin゛ 2011-07-08 09:00
不錯,,#26樓 海市蜃樓 2011-11-02 22:48
學習了。。。#27樓 edwardxh 2011-11-16 09:59
剛剛接觸Socket通信知識,對此問題也比較關心,不知志良兄是否分析一下?