表面上,韓海是進入了修煉,其實他是打開了數據模型庫,觀察起來這次的收穫,他記得在殺死李易龍後,數據模型倉庫傳來響聲,是有東西入庫了。
韓海在倉庫中找尋了半天,終於找到了新增的這個數據模型,這是一張白色的卡片,卡片中央寫着SYSTEM,而在卡片偏上的位置寫着socket.io,當看到這個模型的時候,韓海的心情非常愉快,這個數據模型明顯是一個系統的類庫,而且它的功能也是非常強大的。
可以說句毫不誇張的話,如果沒有socket,那麼互聯網就不存在。
沒錯socket就是網絡傳輸中嵌套字協議,這種協議說白了就是給你一個定量字節的傳輸空間,負責電腦終端間連線的一種協議方案。
而目前大規模應用於瀏覽器的協議,就是基於TCP長連接開發出的http協議,這是一種短連接的協議,原理很簡單一次請求一次返回,然後就斷開連接,而大家使用的聊天軟件,大部分是使用TCP長連接協議作出的軟件。
韓海現在擁有了socket系統庫後,就可以編寫一套IM系統,也就是及時聊天系統(Instant Messaging),這樣也就可以解決團隊協作中,通訊不方便的問題。
末日之後因爲電力設施都被怪物破壞或者失去維護,各種移動終端都失去了作用,現在大家通訊全靠吼,這對於信息的傳播非常不利,而當韓海有了這一套socket系統庫後,他就可以基於自己的系統開發出多人聊天的軟件了。
而且開發出這種軟件後,韓海不僅僅可以自己人使用,也可以販賣給其他人使用,並且賺取錢財,這樣既方便了自己斂財,又給社會提供了服務,一舉多得。
韓海想到這裡,不禁笑了笑,隨後韓海新建了一個項目,然後又新建了6個文件夾,分別是protocol、common、core、server、main、utils,這些文件夾對應了協議模塊、通用模塊、核心模塊、服務模塊、主函數文件夾、工具類存放文件夾。
這一次韓海編寫的是一個稍微大些的項目,其中使用字符數,他預計估計了下,起碼要使用20-30萬之多,也就是要耗費20-30萬字符能量,可見一個聊天系統的服務器實現的難度,並且寫完服務器韓海還需實現客戶端的編寫,這裡也需要耗費大量的字符能量。
不過在守城戰後,韓海字符能量達到了200萬,目前來說還是夠他揮霍的,所以他目前不必爲字符能量擔憂。
然後韓海開始了漫長的編寫,不過好在的是,聊天系統他之前在公司的時候寫過一套,現在也能回想起來,複寫一遍就好了。
韓海所寫的及時聊天系統,主要分三層:協議層、功能層和業務層。
協議層主要是定義服務器和客戶端傳輸數據包時候的約定,這一層還分2層,第一塊是通訊協議層,第二塊是業務協議層。
通訊協議層:主要是通用化的加密解密方案,握手、重連、斷開等約定。
業務協議層:主要是處理某個用戶要與某人通訊,然後給某人發出消息,斷開等等約定。
協議說白了也算一種數據結構,只不過他們傳播的方式是流狀的,而代碼去解析也需要逐步去解析,就好比寫信的時候,我要告訴你一件事情,但是我雷打不動,信的第一行寫的肯定是你的名字,後面纔跟着是我寫給你的內容。
當然沒有寫信那麼簡單,我們可能在主消息體前面加了很多標示,就像之前所說的,第一層用兩個字節使用IM標識,這個是屬於這個通訊系統的佔位符,第二層用四個字節傳入了一個時間,第三層用1個字節傳了一個短整形7,標識這個文本的業務是傳輸消息,第四層用了四個字節放了一個長整形標識之後消息體的字節長度,第五層才能使用剛剛讀到的消息體長度,纔可以拿到定長的消息體。
在這之後,還需要解碼消息體,得到真正的消息,不過這個東西一般寫在客戶端,服務器只負責傳輸就好了。
當然以上的描述只是個栗子,而真正應用中比這些數據更多、更復雜,比如一個用戶傳遞消息給另一個用戶,如果要交給另一個用戶,不僅服務器要識別這個消息體發送人的身份,還要識別傳遞給那個人的是否存在,能不能發送等等。
功能層主要就是進行數據的一些處理,比如以下代碼:
int encodeLong(long long int src,unsigned char **ret,int &len)
{
unsigned char *buf =(unsigned char*)malloc(9);
memset(buf,0,9);
unsigned char *p = buf;
*p++|= LPUSH_FMT_LONG;
*p++|=(src>>56)&0xFF;
*p++|=(src>>48)&0xFF;
*p++|=(src>>40)&0xFF;
*p++|=(src>>32)&0xFF;
*p++|=(src>>24)&0xFF;
*p++|=(src>>16)&0xFF;
*p++|=(src>>8)&0xFF;
*p++|=(src)&0xFF;
len = 9;
*ret = buf;
return 0;
}
這段代碼的作用就是把一個長整型的數據封裝進入字節流,並且字節流的首地上返回給二級指針。
業務模塊就好理解很多了,比如轉發一個客戶端傳遞來的消息,通過用戶id的標示找到相應的用戶,再從用戶註冊在服務器的消息找到相應的客戶端,然後把消息通過socket傳輸給另外的客戶端。
韓海花了整整半夜才完成了服務器的編寫,要不是很多東西他都寫過,也不可能這麼快,一個新手如果寫一個聊天服務器,從入門到上手就需要一個月,當然新手是指的工科畢業生的水平。
接下來該編寫客戶端了,客戶端和服務器就不同了,客戶端需要一個載體,這個韓海早想到了,這個時候豌豆射手的攻擊,已經無法破開普通喪屍的防禦了,所以韓海準備把它改成通訊工具,想想大家每人肩膀上一個豌豆射手,然後對着它的炮筒通話是中什麼樣的畫面。
韓海一想到這個,就感覺有無窮的動力,作爲一個理工男的惡趣,還真不是一般人可以理解的。
韓海回了回神,打開了豌豆射手的數據模型,然後開始了長時間的閱讀,這一次因爲還是改寫炮筒攻擊方位的模塊,所以他是有操作權限的。
但是這一次韓海需要大改這個模塊的函數了,因爲韓海要把攻擊的功能,完全改寫成一個收聽聲音和播放聲音的組建,好在豌豆射手天生有聽覺模型,並且在炮筒上也長着嘴巴,韓海只需要把這兩樣功能模塊,進行取樣和轉發就可以了。
到了這一步,韓海就必須使用鉤子技術了,他一共編寫了2個篡改函數,因爲函數的原型韓海可以看到,所以篡改以後的函數可以無縫對接原來的功能,從而不影響以前的程序。
第一個篡改的是豌豆射手收聽聲音的函數,他只不過是從中截取了每一幀聲音的數據。
第二個篡改的是豌豆射手發聲的函數,這一次他需要在發出聲音的隊裡中,加入自己從socket收到的聲音數據。
豌豆射手聲音的樣板是標準的PCM,也就是Pulse Code Modulation,即爲脈衝編碼調製。
在光纖通信系統中,光纖中傳輸的是二進制光脈衝“0”碼和“1”碼,它由二進制數字信號對光源進行通斷調製而產生。而數字信號是對連續變化的模擬信號進行抽樣、量化和編碼產生的,稱爲PCM(Pulse-code modulation),即脈衝編碼調製。
而這種樣本數據一般數量級比較大,不利於傳輸,所以韓海使用了一個通用壓縮標準AAC進行編碼傳輸,AAC即是高級音頻編碼(Advanced Audio Coding)。
目前韓海可以粗略的實現AAC的編碼步驟,這種壓縮編碼算法是有損失的算法,原理採樣一段時間內的PCM數據,然後使用傅里葉變幻編解碼,聲音其實就是不同頻域的振幅,疊加起來的正弦波,編碼算法其實就是進行時域正弦波疊加成近方型的正弦波,而解碼就是使用傅里葉反變換,把疊加正弦波解碼成原來一段段的正弦波。(這裡只是粗略的進行編解碼)
再之後的步驟,把壓縮後的音頻向服務器進行發送就可以了,再由服務器轉發到另外的客戶端,當客戶端接收到音頻消息的時候,再運行篡改後的發聲函數,這樣就達到了通訊的目的。
當然客戶端也必須建立一套身份標識,否則通訊就無從尋找聯繫人了,這一點韓海已經想到了,當建立模型的時候,韓海可以給每個豌豆射手設置一個數字號碼,當有人想要通訊的時候,在豌豆射手上撥號就可以了,而且系統內部還建立的羣組概念,其實就是聊天羣,聯繫人可以在羣裡發信息與羣組內的所有人通訊。
之後韓海還編寫了一套聊天界面,他把豌豆射手一側綠色的表皮,變成動態的屏幕,這樣用戶就既可以發送聲音也可以發送文字了。(參考QQIM)
目前韓海並沒有開發視頻聊天的功能,因爲視頻的編碼比起聲音來說複雜了不止一點,這是他以前學習中所欠缺的內容,這需要他再學習下H264視頻編碼後纔可以實現,所以這裡他留下了一個釦子,只有等以後再改進了。
做完這些,韓海把socket連接的函數寫好,然後仔仔細細觀察起寫好的代碼來,這是他許久以來養成的習慣,沒有一個程序員,敢說自己寫的程序沒有BUG,如果有人說了,那麼只是他沒發現而已。
沒一會兒,韓海又修改了幾處地方,然後仔仔細細再看了一遍,直到發現不了問題後,他才送了一口氣。
在這個時候,他才感覺到一股睏意襲來,顯然大量代碼的編寫,耗費了他大量的精力,這使得他心中一驚,因爲明天還有事情做,想到這裡他不敢怠慢,開始放空自己的腦袋,真正不去思想東西,這才沉沉的睡了過去。