我知道這樣的文章在博客園已經多的大家都不想看了,但是這是我的系列文章開始,請各位大神見諒了。
多線程,線程執行器,(詳見),socket通信相關 (詳見)
本人blog相關文章測試代碼,示例,完整版svn地址。(http://code.taobao.org/svn/flynetwork_csharp/trunk/Flynetwork/BlogTest)
提供全部源碼功能塊。希望各位大神,提供寶貴意見。
莫倩,完成了多線程輔助類庫完整功能(或許后期會有bug需要修復或者優化),socket完成了tcp和http服務監聽功能,udp和websocket還在完善的狀態中。
如果有通信愿意和我一起完善這個輔助類庫,請聯系我,開通svn授權。
所以源碼免費提供使用,歡迎各位愛好者,加入到項目中,無論是個人,企業,商用,都不限制。唯一要求請保留以下字樣。謝謝合作~!
1 /**2 * 3 * @author 失足程序員4 * @Blog http://m.survivalescaperooms.com/ty408/5 * @mail 492794628@QQ.com6 * @phone 138821220197 * 8 */
好了開始我們的話題
在服務器項目開發中,最總要的也就是登陸問題了或者說叫授權問題。
我們先創建一個console的程序
引用我的兩個庫Sz.Network.SocketPool ,Sz.Network.ThreadPool 分別是socket 幫助庫線程幫助庫。
Sz表示失足的意思。請見諒。偶喜歡上這個代號了“失足程序員”
我們先創建一個消息處理器MessagePool

1 public class MessagePool : ISocketPool 2 { 3 public void ActiveSocket(IOsession client) 4 { 5 } 6 7 public void CloseSocket(IOSession client) 8 { 9 10 }11 12 public void ReadMessage(IOSession client, SocketMessage message)13 {14 15 }16 17 18 public void ActiveHttp(HttpClient client, string bind, Dictionary<string, string> parms)19 {20 if (bind.Equals("/test/"))21 {22 ThreadManager.GetInstance.AddTask(ServerManager.LoginThreadID, new LoginHttpHandler(client, parms));23 }24 }25 26 public void IOSessionException(IOSession client, Exception exception)27 {28 Logger.Error("內部錯誤", exception);29 }30 31 public void HttpException(HttpClient client, Exception exception)32 {33 Logger.Error("內部錯誤", exception);34 }35 }View Code然后在mian函數里面加入
1 Sz.Network.SocketPool.ListenersBox.GetInstance.SetParams(new MessagePool(), typeof(MarshalEndian));2 Sz.Network.SocketPool.ListenersBox.GetInstance.Start("tcp:*:9527", "http://*:8001/test/");這樣我們就開啟了服務器的監聽,這里簡單介紹一下為什么我創建了tcp和http的兩個監聽呢?
這是因為經驗和工作關系,因為我是致力于游戲開發的,服務器端需要創建兩個tcp通常是用于正常通信的,而http監聽的登陸模塊,或者一些非總要性數據交換以及第三方登陸授權需要開啟的。同樣還因為http是短連接,無需保存通信對象,減少了系統消耗,和tcp數量級消耗。
如果你不理解可以不加入http的監聽的。直接看tcp的socket。
1 [2015-04-15 18:12:09:899:Info ] Start Listen Tcp Socket -> 0.0.0.0:95272 [2015-04-15 18:12:09:906:Info ] Start Listen Http Socket -> 0.0.0.0:8001/test/
運行程序,輸出。
開啟了tcp和http的監聽,http我們今天暫時忽略其作用吧。
我們開始準備登陸模塊的開發,同學都知道登陸首先要面臨的就是多點同時登陸問題。
如果加入 lock 來防止多點同時登陸,那么勢必照成服務器卡頓。吞吐量不高等因素。那么我們考慮把這一塊加入到單獨的線程驚喜處理。也就是幫登陸和登出,放到同一個線程處理。不用加鎖,也能做到防止多點同時登陸。
接下來我們需要從Sz.Network.ThreadPool 庫中取出一個線程
public static readonly long LoginThreadID = ThreadManager.GetInstance.GetThreadModel("登陸處理器");用于控制登陸和登出
創建一個CloseTcpHandler 處理鏈接端口的處理程序需要繼承Sz.Network.ThreadPool 下面的TaskBase

1 public class CloseTcpHandler : TaskBase 2 { 3 4 IOSession client; 5 SocketMessage message; 6 7 public CloseTcpHandler(IOSession client) 8 : base("Tcp登陸處理") 9 {10 this.client = client;11 }12 13 14 public override void TaskRun()15 {16 17 }18 }View Code那么我們修改一下MessagePool 類
public void ActiveSocket(IOSession client) { //client.SendMsg(new SocketMessage(1, System.Text.UTF8Encoding.Default.GetBytes("Holle Server!client"))); } public void CloseSocket(IOSession client) { ThreadManager.GetInstance.AddTask(ServerManager.LoginThreadID, new CloseTcpHandler(client)); }這樣斷開鏈接處理就交到了ServerManager.LoginThreadID 這個線程里面處理了
我們再來創建一下LoginTcpHandler 處理登陸程序 需要繼承Sz.Network.ThreadPool 下面的TaskBase
View Code修改MessagePool 類 處理登陸消息
1 public void ReadMessage(IOSession client, SocketMessage message) 2 { 3 switch (message.MsgID) 4 { 5 case 1://登陸 6 case 2: 7 ThreadManager.GetInstance.AddTask(ServerManager.LoginThreadID, new LoginTcpHandler(client, message)); 8 break; 9 default:10 Logger.Error("未綁定消息ID " + message.MsgID);11 break;12 }13 }這里是我自定義消息ID是1和2的一個是登陸一個是登出。
這樣就把登陸的事件也交給了ServerManager.LoginThreadID 這個線程里面處理了
LoginTcpHandler taskrun方法

1 public override void TaskRun() 2 { 3 using (MemoryStream msReader = new MemoryStream(message.MsgBuffer)) 4 { 5 using (System.IO.BinaryReader srReader = new BinaryReader(msReader, UTF8Encoding.Default)) 6 { 7 using (MemoryStream msWriter = new MemoryStream()) 8 { 9 using (System.IO.BinaryWriter srWriter = new BinaryWriter(msWriter, UTF8Encoding.Default))10 {11 switch (message.MsgID)12 {13 case 1://登陸 14 string username = srReader.ReadString();15 if (!LoginManager.GetInstance.LoginNames.Contains(username))16 {17 LoginManager.GetInstance.LoginNames.Add(username);18 if (!LoginManager.GetInstance.Loginips.ContainsKey(client.ID))19 {20 LoginManager.GetInstance.LoginIPs[client.ID] = username;21 LoginManager.GetInstance.Sessions.Add(client);22 }23 srWriter.Write(true);24 srWriter.Write(username + " 登陸聊天室");25 Logger.Info(client.RemoteEndPoint + " " + username + " 登陸成功");26 SocketMessage sm = new SocketMessage(message.MsgID, msWriter.GetBuffer());27 ServerManager.GetInstance.Tell_All(sm);28 }29 else30 {31 srWriter.Write(false);32 srWriter.Write("登錄名稱重復,請換一個");33 Logger.Info(client.RemoteEndPoint + " " + username + " 登錄名稱重復!");34 SocketMessage sm
新聞熱點
疑難解答