上一篇文章,讲解了简单的登陆情况。接下来我们继续讲解登陆模块。

在正常的游戏服务器情况下。在尚未登录前可以查看服务器大区情况,登陆后也可以查看服务器大区情况,然后选择大区服务器。进行登录操作。

这样的情况就需要我们有一个登录服务器来负责,目前大区服务器的状态,是正常。拥挤,爆满。还是停服维护。那么这样登录服务器,如果进行控制和输出呢?

如何与大区服务器正常进行通信已经同步登录状态呢?

登录服务器,可以看作是我们其他大区服务器的网关服务器。那么势必为了保证服务器的高可用性,已经内存等资源消耗。我们这里的数据交换肯定不能依赖于socket连接进行。这样消耗会很大,这里其实只需要查看服务器状态和登陆即可。那么我们需要http就能顺利完成的工作。无需长连接,就无需考虑连接状态。

那么这种情况,http虽然能减少消耗,返回服务器状态。但是也要保证玩家的登陆状态,还要与其他服务器保持同步状态。那么基于IIS或者tomcat肯定是无法完成了。

这里就有了自定义开发的基于Socket 的服务器程序来今天http协议监听。具体的文章之前有过介绍(详见)。

今天我们就来真正完成http登陆模块。

  Sz.Network.SocketPool.ListenersBox.GetInstance.SetParams(new MessagePool(), typeof(MarshalEndian));
             Sz.Network.SocketPool.ListenersBox.GetInstance.Start("tcp:*:9527", "http://*:8001/login/");

依旧是上一篇文章的代码,进行http的绑定的 login 进行监听。

在 MessagePool 类的  函数

  public void ActiveHttp(HttpClient client, string bind, Dictionary<string, string> parms)
         {
             if (bind.Equals("/login/"))
             {
                 string strHtml = "ret=";
                 strHtml += "Login OK!";
                 client.OutputStream.WriteLine(strHtml);
                 client.Close();
             }
         }

这样我们可以判断出,请求 bind 是来至于 login的绑定,后面的 parms 是此处请求的参数信息,不管是post还是get请求方式。这里如果需要了解参数的获取方式请详见以前的文章《C# 利用socekt做到http监听,怎么样才能做到高性能》

那么我们开启服务器先测试一下,

可以看到,我们监听login是成功的,

我们可以开始登陆操作了,登陆我们要解决的就是一个http的连接如何保持登陆状态。

这里的灵感来至于腾讯,百度等api接口的思路创建的登陆验证方式。

为了方便进行,我们需要从nuget处获取一个第三方类库 json.net 进行数据的json格式输出。

修改一下 ActiveHttp

 string strHtml = "ret=";
             if (bind.Equals("/login/"))
             {
                 foreach (var item in parms)
                 {
                     Console.WriteLine("参数:"+item.Key + ":" + item.Value);

                 }
                 strHtml += "Login OK!";
             }
             client.OutputStream.WriteLine(strHtml);
             client.Close();

在浏览器输入 http://127.0.0.1:8001/login/?username=test1&pwd=test1&logintime=2015-4-16%2012:00

请不要在意密码是不是明文传输的。

 [-- ::::Info ] Create Http Socket Remote Socket LocalEndPoint: RemoteEndPoint:
 参数:username:test1
 参数:pwd:test1
 参数:logintime:-- :

正常接收到get传来的登陆数据。

我们想创建一个密钥 key值

string key = "89bf54aca24a457ea32a6a0d81cbcc4e";

在创建一个回复类

  class LoginRet
         {
             public string Ret { get; set; }

             public string PWDKey { get; set; }
         }
         public void ActiveHttp(HttpClient client, string bind, Dictionary<string, string> parms)
         {
             LoginRet loginRet = new LoginRet();
             if (bind.Equals("/login/"))
             {
                 if (parms["username"] == "test1" && parms["pwd"] == "test1")
                 {
                     loginRet.Ret = "Login OK!";
                     string pwdkey = parms["username"] + parms["pwd"] + key + parms["logintime"];
                     byte[] pwdkeyBuffer = UTF8Encoding.Default.GetBytes(pwdkey);
                     loginRet.PWDKey = Convert.ToBase64String(pwdkeyBuffer);
                     Logger.Info("用户 " + parms["username"] + " 登陆完成 密钥:" + loginRet.PWDKey);
                 }
                 else { loginRet.Ret = "Login Error!"; }
             }
             else
             {
                 loginRet.Ret = "Login Error!";
             }
             string jsonStr = Newtonsoft.Json.JsonConvert.SerializeObject(loginRet);
             client.OutputStream.WriteLine(jsonStr);
             client.Close();
         }

修改一下处理方法,这里我采用的加密方式,仅仅是最简单的,就是把 登陆名 + 登陆密码 + 密钥 + 登录时间 转换成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);
            }

修改一下访问模式

客户端登陆代码更改为

 BufferWriter bw = );
             bw.Write(ConnectManager.GetInstance.Ret.PWDKey);//发送登陆凭据
             bw.Write("test1");//发送用户名
             bw.Write("2015-4-16 12:00");//发送时间
             bw.Write(this.username.Text.TrimEnd());
             ConnectManager.GetInstance.Client.SendMsg(bw.GetMessage());
             bw.Dispose();

服务器socket 登陆验证。

 string pwdkey = this.bufferReader.ReadString();
                     string username = this.bufferReader.ReadString();
                     string loginTime = this.bufferReader.ReadString();
                     string name = this.bufferReader.ReadString();

                     if (pwdkey == Convert.ToBase64String(UTF8Encoding.Default.GetBytes(username + ServerManager.key + loginTime)))
                     {
                         if (!LoginManager.GetInstance.LoginNames.Contains(username))
                         {
                             LoginManager.GetInstance.LoginNames.Add(username);
                             if (!LoginManager.GetInstance.LoginIPs.ContainsKey(Session.ID))
                             {
                                 LoginManager.GetInstance.LoginIPs[Session.ID] = username;
                                 LoginManager.GetInstance.Sessions.Add(Session);
                             }
                             srWriter.Write(true);
                             srWriter.Write(name + " 登陆聊天室");
                             Logger.Info(Session.RemoteEndPoint + " " + name + " 登陆成功");
                             ServerManager.GetInstance.Tell_All(srWriter.GetMessage());
                         }
                         else
                         {
                             srWriter.Write(false);
                             srWriter.Write("登录名称重复,请换一个");
                             Logger.Info(Session.RemoteEndPoint + " " + name + " 登录名称重复!");
                             Session.SendMsg(srWriter.GetMessage());
                         }
                     }

此时我们在socket登陆验证只需要验证传入的参数,pwdkey能否生成相同的。则为登陆成功。

完成了正常的游戏登陆流程,莫倩,页游,手游,都是第三方运营平台,登陆账号和密码,都是第三方的。如果需要http登陆,密钥key到游戏内部验证。

一步一步开发Game服务器(二)登陆2的更多相关文章

  1. 一步一步开发Game服务器(三)加载脚本和服务器热更新(二)完整版

    上一篇文章我介绍了如果动态加载dll文件来更新程序 一步一步开发Game服务器(三)加载脚本和服务器热更新 可是在使用过程中,也许有很多会发现,动态加载dll其实不方便,应为需要预先编译代码为dll文 ...

  2. 一步一步开发Game服务器(二)完成登陆,聊天

    我知道这样的文章在博客园已经多的大家都不想看了,但是这是我的系列文章开始,请各位大神见谅了. 多线程,线程执行器,(详见),socket通信相关 (详见) 本人blog相关文章测试代码,示例,完整版s ...

  3. 一步一步开发Game服务器(四)地图线程

    时隔这么久 才再一次的回归正题继续讲解游戏服务器开发. 开始讲解前有一个问题需要修正.之前讲的线程和定时器线程的时候是分开的. 但是真正地图线程与之前的线程模型是有区别的. 为什么会有区别呢?一个地图 ...

  4. 一步一步跟我学DeviceOne开发 - 仿微信应用(一,二,三)

    这是一个系列的文档,长期目标是利用DeviceOne开发一些目前使用广泛的优质手机应用,我们会最大化的实现这些应用的每一个功能和细节,不只停留在简单的UI模仿和Demo阶段,而是一个基本可以使用的实际 ...

  5. 一步一步开发Game服务器(一)

    什么是服务器?对于很多人来说也许只是简单成为在服务器端运行的程序的确如此,服务器通常意义就是说在服务器端运行的程序而已.那么我们怎么理解和分析游戏服务器哪? 传统意义上来说,程序运行后,正常流程, 启 ...

  6. JAVA+PHP+阿里云组件纯手工实现POP、SMTP、IMAP开发邮件服务器(二)

    java开发邮件服务器的接收模块 用java建立socket服务端,监听端口25,实现SMTP协议.即可完成邮件服务器的接收模块. 这里要注意的是,SMTP协议其实可以分为两种.一种是你用手机.PC等 ...

  7. 跟我一步一步开发自己的Openfire插件

    http://www.blogjava.net/hoojo/archive/2013/03/07/396146.html 跟我一步一步开发自己的Openfire插件 这篇是简单插件开发,下篇聊天记录插 ...

  8. xmppmini 项目详解:一步一步从原理跟我学实用 xmpp 技术开发 2.登录的实现

    第二章登录的实现 金庸<倚天屠龙记> 张三丰缓缓摇头,说道:“少林派累积千年,方得达成这等绝技,决非一蹴而至,就算是绝顶聪明之人,也无法自创.”他顿了一顿,又道:“我当年在少林寺中住过,只 ...

  9. 一步一步实现HTTP服务器-开篇

    缘起 翻开清单,一条条计划一直列在那里,一天又一天,不知道什么时候写下了它,也知不道什么时候完成它,它一直在那静静的等待着. 静下心来,反思自己,才发现自己是多么的无知,多么的没有毅力.设定了无数目标 ...

随机推荐

  1. 自写函数VB6 STUFF函数 和 VB.net 2010 STUFF函数 详解

    '*************************************************************************'**模 块 名:自写函数VB6 STUFF函数 和 ...

  2. .NET Framework 4.5.2 静默安装参数

    Microsoft .NET Framework 4.5.2 是针对 Microsoft .NET Framework 4.Microsoft .NET Framework 4.5 和 Microso ...

  3. 思维导图FreeMind

    什么是MindMap? MindMap(被译成思维导图或心智图)是一种思维工具,由英国的记忆之父托尼-博赞发明. MindMap是一种新的思维模式,它将左脑的逻辑.顺序.条例.文字.数字,以及右脑的图 ...

  4. 开发便于运维的Windows服务

    过去几个月,DevOps on Windows网站推出了一系列文章,详细讲解了开发者应怎样创建便于运维的Windows服务.这一系列文章详细分析了如何克服在运维部门看来最困难的部分:Windows服务 ...

  5. LibSVM for Python 使用

    经历手写SVM的惨烈教训(还是太年轻)之后,我决定使用工具箱/第三方库 Python libsvm的GitHub仓库 LibSVM是开源的SVM实现,支持C, C++, Java,Python , R ...

  6. EF:打开Oracle连接时报错

    基础提供程序在 Open 上失败. The underlying provider failed on Open. 解决:安装最新的ODTwithODAC121024.

  7. Golang与C#之switch区别

    Golang与C#之switch区别 Go是Google开发的一种编译型,可并行化,并具有垃圾回收功能的编程语言. C#是微软公司发布的一种面向对象的.运行于.NET Framework之上的高级程序 ...

  8. 以Excel 作为Data Source,将data导入db

    将Excel作为数据源,将数据导入db,是SSIS的一个简单的应用,下图是示例Excel,数据列是code和name 第一部分,Excel中的数据类型是数值类型 1,使用SSDT创建一个package ...

  9. 把w3schools英文版的所有属性扒下来了,免费分享。

    为了方便查手册等,把w3schools上的所以属性弄成json版的了,到时候再修改一下,查起来就比较方便了,这里免费分享一下.一共为两份,一份为选择器部分,还有一部分是属性. 选择器部分json 属性 ...

  10. Hello World of OpenCascade

    Hello World of OpenCascade eryar@163.com 摘要Abstract:以一个经典的Hello World程序为例开始对开源几何造型内核OpenCascade的学习. ...