1. 程式人生 > >一步一步開發Game伺服器(二)登陸2

一步一步開發Game伺服器(二)登陸2

上一篇文章,講解了簡單的登陸情況。接下來我們繼續講解登陸模組。

在正常的遊戲伺服器情況下。在尚未登入前可以檢視伺服器大區情況,登陸後也可以檢視伺服器大區情況,然後選擇大區伺服器。進行登入操作。

這樣的情況就需要我們有一個登入伺服器來負責,目前大區伺服器的狀態,是正常。擁擠,爆滿。還是停服維護。那麼這樣登入伺服器,如果進行控制和輸出呢?

如何與大區伺服器正常進行通訊已經同步登入狀態呢?

登入伺服器,可以看作是我們其他大區伺服器的閘道器伺服器。那麼勢必為了保證伺服器的高可用性,已經記憶體等資源消耗。我們這裡的資料交換肯定不能依賴於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到遊戲內部驗證。