一步一步开发Game服务器(二)登陆2
上一篇文章,讲解了简单的登陆情况。接下来我们继续讲解登陆模块。
在正常的游戏服务器情况下。在尚未登录前可以查看服务器大区情况,登陆后也可以查看服务器大区情况,然后选择大区服务器。进行登录操作。
这样的情况就需要我们有一个登录服务器来负责,目前大区服务器的状态,是正常。拥挤,爆满。还是停服维护。那么这样登录服务器,如果进行控制和输出呢?
如何与大区服务器正常进行通信已经同步登录状态呢?
登录服务器,可以看作是我们其他大区服务器的网关服务器。那么势必为了保证服务器的高可用性,已经内存等资源消耗。我们这里的数据交换肯定不能依赖于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的更多相关文章
- 一步一步开发Game服务器(三)加载脚本和服务器热更新(二)完整版
上一篇文章我介绍了如果动态加载dll文件来更新程序 一步一步开发Game服务器(三)加载脚本和服务器热更新 可是在使用过程中,也许有很多会发现,动态加载dll其实不方便,应为需要预先编译代码为dll文 ...
- 一步一步开发Game服务器(二)完成登陆,聊天
我知道这样的文章在博客园已经多的大家都不想看了,但是这是我的系列文章开始,请各位大神见谅了. 多线程,线程执行器,(详见),socket通信相关 (详见) 本人blog相关文章测试代码,示例,完整版s ...
- 一步一步开发Game服务器(四)地图线程
时隔这么久 才再一次的回归正题继续讲解游戏服务器开发. 开始讲解前有一个问题需要修正.之前讲的线程和定时器线程的时候是分开的. 但是真正地图线程与之前的线程模型是有区别的. 为什么会有区别呢?一个地图 ...
- 一步一步跟我学DeviceOne开发 - 仿微信应用(一,二,三)
这是一个系列的文档,长期目标是利用DeviceOne开发一些目前使用广泛的优质手机应用,我们会最大化的实现这些应用的每一个功能和细节,不只停留在简单的UI模仿和Demo阶段,而是一个基本可以使用的实际 ...
- 一步一步开发Game服务器(一)
什么是服务器?对于很多人来说也许只是简单成为在服务器端运行的程序的确如此,服务器通常意义就是说在服务器端运行的程序而已.那么我们怎么理解和分析游戏服务器哪? 传统意义上来说,程序运行后,正常流程, 启 ...
- JAVA+PHP+阿里云组件纯手工实现POP、SMTP、IMAP开发邮件服务器(二)
java开发邮件服务器的接收模块 用java建立socket服务端,监听端口25,实现SMTP协议.即可完成邮件服务器的接收模块. 这里要注意的是,SMTP协议其实可以分为两种.一种是你用手机.PC等 ...
- 跟我一步一步开发自己的Openfire插件
http://www.blogjava.net/hoojo/archive/2013/03/07/396146.html 跟我一步一步开发自己的Openfire插件 这篇是简单插件开发,下篇聊天记录插 ...
- xmppmini 项目详解:一步一步从原理跟我学实用 xmpp 技术开发 2.登录的实现
第二章登录的实现 金庸<倚天屠龙记> 张三丰缓缓摇头,说道:“少林派累积千年,方得达成这等绝技,决非一蹴而至,就算是绝顶聪明之人,也无法自创.”他顿了一顿,又道:“我当年在少林寺中住过,只 ...
- 一步一步实现HTTP服务器-开篇
缘起 翻开清单,一条条计划一直列在那里,一天又一天,不知道什么时候写下了它,也知不道什么时候完成它,它一直在那静静的等待着. 静下心来,反思自己,才发现自己是多么的无知,多么的没有毅力.设定了无数目标 ...
随机推荐
- .NET垃圾回收 – 原理浅析
在开发.NET程序过程中,由于CLR中的垃圾回收(garbage collection)机制会管理已分配的对象,所以程序员就可以不用关注对象什么时候释放内存空间了.但是,了解垃圾回收机制还是很有必要的 ...
- 《HiWind企业快速开发框架实战》(3)使用HiWind创建和管理菜单
<HiWind企业快速开发框架实战>(3)使用HiWind创建和管理菜单 关于HiWind HiWind企业快速开发框架,是基于.NET+EasyUi(支持各种前端扩展,后面将扩展Boot ...
- 纯命令行的编辑利器:用好 awk 与 sed
awk 的基本语法 awk 是模式查找与处理语言,是文本处理的利器.使用 awk 可以只用一条简单的命令完成复杂的文本数据处理. awk 命令的基本结构为: awk '模式 {处理}' 文件 比如,打 ...
- 论HTML5 Audio 标签歌词同步的实现
HTML5草案里面其实有原生的字幕标签(<track> Tag)的,但使用的是vtt格式的文件,非常规的字幕(.sub, .srt)或歌词文件(.lrc). 用法如下(代码来自W3Scho ...
- Atom使用纪要
一直在更新的原文地址奉上,欢迎PR:Atom使用纪要 官网地址: atom.io 目前(2015/7/29)Atom主题已有725个:Package已有2394 简单交代背景 Atom 是 Githu ...
- Leetcode 刷题计划
Two Sum 21.4% Medium Given an array of integers, return indices of the two numbers such that t ...
- Solr的原理及在项目中的使用实例.
前面已经讲过 如果安装及配置Solr服务器了, 那么现在我们就来正式在代码中使用Solr.1,这里Solr主要是怎么使用的呢? 当我们在前台页面搜索商品名称关键词时, 我们这时是在Solr库中去查找 ...
- iOS-常见问题
11.21常见问题 一storyboard连线问题 产生原因:将与storyboard关联的属性删除了,但是storyboard中还保持之前所关联的属性. 解决: 点击view controller ...
- iOS----集成ijkplayer视频直播
ijkplayer 是一款做视频直播的框架, 基于ffmpeg, 支持 Android 和 iOS, 网上也有很多集成说明, 但是个人觉得还是不够详细, 在这里详细的讲一下在 iOS 中如何集成ijk ...
- SQL之case when then用法
case具有两种格式.简单case函数和case搜索函数. 按 Ctrl+C 复制代码 这两种方式,可以实现相同的功能.简单case函数的写法相对比较简洁,但是和case搜索函数相比,功能方面会有些限 ...