上一篇文章,講解了簡單的登陸情況。接下來我們繼續講解登陸模塊。
在正常的游戲服務器情況下。在尚未登錄前可以查看服務器大區情況,登陸後也可以查看服務器大區情況,然後選擇大區服務器。進行登錄操作。
這樣的情況就需要我們有一個登錄服務器來負責,目前大區服務器的狀態,是正常。擁擠,爆滿。還是停服維護。那麼這樣登錄服務器,如果進行控制和輸出呢?
如何與大區服務器正常進行通信已經同步登錄狀態呢?
登錄服務器,可以看作是我們其他大區服務器的網關服務器。那麼勢必為了保證服務器的高可用性,已經內存等資源消耗。我們這裡的數據交換肯定不能依賴於socket連接進行。這樣消耗會很大,這裡其實只需要查看服務器狀態和登陸即可。那麼我們需要http就能順利完成的工作。無需長連接,就無需考慮連接狀態。
那麼這種情況,http雖然能減少消耗,返回服務器狀態。但是也要保證玩家的登陸狀態,還要與其他服務器保持同步狀態。那麼基於IIS或者tomcat肯定是無法完成了。
這裡就有了自定義開發的基於Socket 的服務器程序來今天http協議監聽。具體的文章之前有過介紹(詳見)。
今天我們就來真正完成http登陸模塊。
1 Sz.Network.SocketPool.ListenersBox.GetInstance.SetParams(new MessagePool(), typeof(MarshalEndian)); 2 Sz.Network.SocketPool.ListenersBox.GetInstance.Start("tcp:*:9527", "http://*:8001/login/");
依舊是上一篇文章的代碼,進行http的綁定的 login 進行監聽。
在 MessagePool 類的 函數
1 public void ActiveHttp(HttpClient client, string bind, Dictionary<string, string> parms) 2 { 3 if (bind.Equals("/login/")) 4 { 5 string strHtml = "ret="; 6 strHtml += "Login OK!"; 7 client.OutputStream.WriteLine(strHtml); 8 client.Close(); 9 } 10 }
這樣我們可以判斷出,請求 bind 是來至於 login的綁定,後面的 parms 是此處請求的參數信息,不管是post還是get請求方式。這裡如果需要了解參數的獲取方式請詳見以前的文章 《C# 利用socekt做到http監聽,怎麼樣才能做到高性能》
那麼我們開啟服務器先測試一下,
可以看到,我們監聽login是成功的,
我們可以開始登陸操作了,登陸我們要解決的就是一個http的連接如何保持登陸狀態。
這裡的靈感來至於騰訊,百度等api接口的思路創建的登陸驗證方式。
為了方便進行,我們需要從nuget處獲取一個第三方類庫 json.net 進行數據的json格式輸出。
修改一下 ActiveHttp
1 string strHtml = "ret="; 2 if (bind.Equals("/login/")) 3 { 4 foreach (var item in parms) 5 { 6 Console.WriteLine("參數:"+item.Key + ":" + item.Value); 7 8 } 9 strHtml += "Login OK!"; 10 } 11 client.OutputStream.WriteLine(strHtml); 12 client.Close();
在浏覽器輸入 http://127.0.0.1:8001/login/?username=test1&pwd=test1&logintime=2015-4-16%2012:00
請不要在意密碼是不是明文傳輸的。
1 [2015-04-16 12:10:38:287:Info ] Create Http Socket Remote Socket LocalEndPoint:127.0.0.1:8001 RemoteEndPoint:127.0.0.1:4332 2 參數:username:test1 3 參數:pwd:test1 4 參數:logintime:2015-4-16 12:00
正常接收到get傳來的登陸數據。
我們想創建一個密鑰 key值
string key = "89bf54aca24a457ea32a6a0d81cbcc4e";
在創建一個回復類
1 class LoginRet 2 { 3 public string Ret { get; set; } 4 5 public string PWDKey { get; set; } 6 }
1 public void ActiveHttp(HttpClient client, string bind, Dictionary<string, string> parms) 2 { 3 LoginRet loginRet = new LoginRet(); 4 if (bind.Equals("/login/")) 5 { 6 if (parms["username"] == "test1" && parms["pwd"] == "test1") 7 { 8 loginRet.Ret = "Login OK!"; 9 string pwdkey = parms["username"] + parms["pwd"] + key + parms["logintime"]; 10 byte[] pwdkeyBuffer = UTF8Encoding.Default.GetBytes(pwdkey); 11 loginRet.PWDKey = Convert.ToBase64String(pwdkeyBuffer); 12 Logger.Info("用戶 " + parms["username"] + " 登陸完成 密鑰:" + loginRet.PWDKey); 13 } 14 else { loginRet.Ret = "Login Error!"; } 15 } 16 else 17 { 18 loginRet.Ret = "Login Error!"; 19 } 20 string jsonStr = Newtonsoft.Json.JsonConvert.SerializeObject(loginRet); 21 client.OutputStream.WriteLine(jsonStr); 22 client.Close(); 23 }
修改一下處理方法,這裡我采用的加密方式,僅僅是最簡單的,就是把 登陸名 + 登陸密碼 + 密鑰 + 登錄時間 轉換成64為字符串,(這裡各位同學可以根據自己項目的實際情況和需求改為md5也好,自己寫算法也好,都可以)
這樣就得到了登陸成功後的憑證,拿著這個憑證可以在我們任何服務器相同規則下進行無需第二次驗證登陸。
在浏覽器輸入 http://127.0.0.1:8001/login/?username=test1&pwd=test1&logintime=2015-4-16%2012:00再一次使用這個 url 測試
接下來我們拋棄浏覽器,用客戶端程序來試試,
WebRequest request = WebRequest.Create("http://127.0.0.1:8001/login/?username=test1&pwd=test1&logintime=2015-4-16%2012:00"); request.Method = "GET"; string str = new System.IO.StreamReader(request.GetResponse().GetResponseStream(), UTF8Encoding.Default).ReadToEnd(); Ret = Newtonsoft.Json.JsonConvert.DeserializeObject<LoginRet>(str); if (Ret != null && Ret.Ret) { ConnectManager.GetInstance.AddMsg("登陸成功" + Ret.PWDKey); }
修改一下訪問模式
客戶端登陸代碼更改為
1 BufferWriter bw = new BufferWriter(1); 2 bw.Write(ConnectManager.GetInstance.Ret.PWDKey);//發送登陸憑據 3 bw.Write("test1");//發送用戶名 4 bw.Write("2015-4-16 12:00");//發送時間 5 bw.Write(this.username.Text.TrimEnd()); 6 ConnectManager.GetInstance.Client.SendMsg(bw.GetMessage()); 7 bw.Dispose();
服務器socket 登陸驗證。
1 string pwdkey = this.bufferReader.ReadString(); 2 string username = this.bufferReader.ReadString(); 3 string loginTime = this.bufferReader.ReadString(); 4 string name = this.bufferReader.ReadString(); 5 6 if (pwdkey == Convert.ToBase64String(UTF8Encoding.Default.GetBytes(username + ServerManager.key + loginTime))) 7 { 8 if (!LoginManager.GetInstance.LoginNames.Contains(username)) 9 { 10 LoginManager.GetInstance.LoginNames.Add(username); 11 if (!LoginManager.GetInstance.LoginIPs.ContainsKey(Session.ID)) 12 { 13 LoginManager.GetInstance.LoginIPs[Session.ID] = username; 14 LoginManager.GetInstance.Sessions.Add(Session); 15 } 16 srWriter.Write(true); 17 srWriter.Write(name + " 登陸聊天室"); 18 Logger.Info(Session.RemoteEndPoint + " " + name + " 登陸成功"); 19 ServerManager.GetInstance.Tell_All(srWriter.GetMessage()); 20 } 21 else 22 { 23 srWriter.Write(false); 24 srWriter.Write("登錄名稱重復,請換一個"); 25 Logger.Info(Session.RemoteEndPoint + " " + name + " 登錄名稱重復!"); 26 Session.SendMsg(srWriter.GetMessage()); 27 } 28 }
此時我們在socket登陸驗證只需要驗證傳入的參數,pwdkey能否生成相同的。則為登陸成功。
完成了正常的游戲登陸流程,莫倩,頁游,手游,都是第三方運營平台,登陸賬號和密碼,都是第三方的。如果需要http登陸,密鑰key到游戲內部驗證。