坦白講,咱們公司其實沒啥技術實力,之因此還能不斷接到各類項目,全憑咱們老闆神通廣大!要知道他每次的飯局上可都是些什麼人物!html
可是項目接下一大把,就憑咱哥兒幾個的水平,想要獨立自主、保質保量保期地一個個作出來,那也是有點難以置信。以前咱也跟老闆反映過這個困難,建議他再召兩個高手過來。不過領導雖然書讀的很少,有一句古訓卻是背得特別熟——「君子生非異也,善假於物也」。因此我們公司一直奉行拿來主義。api
園子裏的這個GGTalk——C#開源即時通信系統,我們前先後後用它移花接木作的IM項目也不下三四個了。初次入手的時候,洋洋代碼,多少感受有些難以把握。不過一來二去,理清了頭緒,也就盡收眼底了。安全
相信跟咱們同樣想要利用GGTalk的同窗大有人在,因而我打算寫這樣一個《GGTalk——C#開源即時通信系統源碼介紹系列》,把本身對GGTalk的梳理分享給你們,讓你們更容易上手。架構
那接下來咱們就言歸正傳。app
如圖,GGTalk中有4個項目,第一個「GGTalk」是客戶端項目;「GGTalk.Core」是客戶端和服務端共用的一些類,主要包括一些數據實體,還有一些通訊協議類;「GGTalk.Server」是服務端項目;「JustLib」是做者封裝的一些經常使用類和控件。tcp
GGTalk採用Remoting技術來完成註冊。ide
namespace GGTalk { /// <summary> /// 用於提供註冊服務的Remoting接口。 /// </summary> public interface IRemotingService :IChatRecordPersister { RegisterResult Register(GGUser user); /// <summary> /// 根據ID或Name搜索用戶【徹底匹配】。 /// </summary> List<GGUser> SearchUser(string idOrName); /// <summary> /// 發送系統通知給全部在線用戶。 /// </summary> void SendSystemNotify(string title, string content); } }
namespace GGTalk.Server { internal class RemotingService :MarshalByRefObject, IRemotingService { private GlobalCache globalCache; private IRapidServerEngine rapidServerEngine; public RemotingService(GlobalCache db ,IRapidServerEngine engine) { this.globalCache = db; this.rapidServerEngine = engine; } public RegisterResult Register(GGUser user) { try { if (this.globalCache.IsUserExist(user.UserID)) { return RegisterResult.Existed; } this.globalCache.InsertUser(user); return RegisterResult.Succeed; } catch (Exception ee) { return RegisterResult.Error; } } public List<GGUser> SearchUser(string idOrName) { return this.globalCache.SearchUser(idOrName); } public override object InitializeLifetimeService() { return null; } } }
#region 發佈用於註冊的Remoting服務 RemotingConfiguration.Configure("GGTalk.Server.exe.config", false); RemotingService registerService = new Server.RemotingService(globalCache ,Program.RapidServerEngine); RemotingServices.Marshal(registerService, "RemotingService"); #endregion
服務端配置文件:學習
<system.runtime.remoting> <application> <channels> <!--用戶註冊Remoting服務端口--> <channel ref="tcp" port="4500" > <serverProviders> <provider ref="wsdl" /> <formatter ref="soap" typeFilterLevel="Full" /> <formatter ref="binary" typeFilterLevel="Full" /> </serverProviders> <clientProviders> <formatter ref="binary" /> </clientProviders> </channel> </channels> </application> </system.runtime.remoting>
int registerPort = int.Parse(ConfigurationManager.AppSettings["RemotingPort"]); this.remotingService = (IRemotingService)Activator.GetObject(typeof(IRemotingService), string.Format("tcp://{0}:{1}/RemotingService", ConfigurationManager.AppSettings["ServerIP"], registerPort)); ;
1.Remoting使用中的三要素:this
1.一個可遠程處理的對象。spa
2.一個服務端應用程序域用(也叫宿主應用程序域中),於偵聽針對該對象的請求。
3.一個客戶端應用程序域,用於發出針對該對象的請求。
2.代理:
代理是一個提供了和真實對象徹底同樣的接口、公共方法、屬性等成員的對象。在運行過程當中,.NET Remoting基於對象元數據生成代理。代理只提供接口,不提供對象的狀態,由於對象的真正狀態在宿主應用程序域中存儲。代理在這裏只轉發調用。轉發調用到一個對象叫封送處理。封送處理的目標是讓客戶端調用服務端時感受不到是在與遠端對象交流,而是與本地對象在交流。若是經過代理來訪問對象,該對象必需是從 MarshalByRefObject抽象類派生。
3.Remoting架構:
1. 用應用程序域
操做系統和運行庫環境一般會在應用程序間提供某種形式的隔離。例如,Microsoft Windows 使用進程來隔離應用程序。爲確保在一個應用程序中運行的代碼不會對其餘不相關的應用程序產生不良影響,這種隔離是必需的。
2.用應用程序域優勢
在一個應用程序中出現的錯誤不會影響其餘應用程序。由於類型安全的代碼不會致使內存錯誤,因此使用應用程序域能夠確保在一個域中運行的代碼不會影響進程中的其餘應用程序。
可以在不中止整個進程的狀況下中止單個應用程序。使用應用程序域使您能夠卸載在單個應用程序中運行的代碼。
在一個應用程序中運行的代碼不能直接訪問其餘應用程序中的代碼或資源。爲了強制實施此隔離,公共語言運行庫禁止在不一樣應用程序域中的對象之間進行直接調用。要在各域之間傳遞對象,能夠複製這些對象,或經過代理訪問這些對象。若是複製對象,那麼對該對象的調用爲本地調用。也就是說,調用方和被引用的對象位於同一應用程序域中。若是經過代理訪問對象,那麼對該對象的調用爲遠程調用。在此狀況下,調用方和被引用的對象位於不一樣的應用程序域中。域間調用所採用的遠程調用基礎結構與兩個進程間的調用或兩臺計算機間的調用的基礎結構相同。所以,被引用的對象的元數據必須對於兩個應用程序域都可用,以便用 JIT 正確編譯該方法調用。若是調用域對被調用對象的元數據沒有訪問權,則編譯可能失敗,並引起類型爲 System.IO.FileNotFound 的異常。
代碼行爲的做用範圍由它運行所在的應用程序決定。換言之,應用程序域將提供應用程序版本策略等配置設置、它所訪問的任意遠程程序集的位置,以及加載到該域中的程序集的位置信息。
向代碼授予的權限能夠由代碼運行所在的應用程序域來控制。
這是該系列的第一篇,一篇博客篇幅有限,能講清楚一兩個問題已經很不錯。要想把GGTalk——C#開源即時通信系統所有講透,恐怕得要上百篇博客纔夠。首先要感謝GGTalk的做者,可以開發出這樣優秀的C#開源即時通信系統,並且無私的開源出來。其次,但願我作的工做也能給你們帶來收穫,一方面能夠方便你們利用GGTalk,另外一方面也爲學習GGTalk的同窗提供一個參考,但願你們能夠從中汲取養分,不只僅是複用這些代碼,也可以從中學到蘊含着的知識與技術。
解讀GGTalk,這個工做很辛苦,但願你們鼓勵,也但願更多的朋友參與其中!