不用网络储存器器外的游戏

游戏无法运行不要慌FXXZ教您解决错误_飞翔单机游戏网
您的位置: →
→ 游戏无法运行不要慌FXXZ教您解决错误
【飞翔导读】各位玩家注意咯,并不是所有不能运行的游戏都是游戏本身的问题哦,看过下些以后相信会对你对于游戏无法运行该怎么处理方面有着非常大的收获。
很多玩家在运行单机游戏的时候都会遇到各式各样的问题导致游戏无法运行。每每看到自己辛苦下了几天几夜的游戏却不能运行的时候不免有点灰心气馁想骂娘。不过各位玩家注意咯,并不是所有不能运行的游戏都是游戏本身的问题哦,看过下些以后相信会对你对于游戏无法运行该怎么处理方面有着非常大的收获。  风险提示:硬盘版资源不能进游戏的几率较大,且需要下载者有一定的计算机操作水平硬盘版游戏报错常见解决办法:  1、下载并安装最新版的DirectX9.0c  2、下载并安装Microsoft .NET Framework 2.0再试(现在某些游戏需要3.0甚至3.5版本)  3、部分游戏需要安装目录中路径是全英文  4、部分游戏需要操作系统用户名全英文  5、彻底关闭瑞星及其后台程序,关闭金山毒霸,推荐卡巴斯基  6、更新XP补丁、更新显卡驱动  7、安装vcredist_x86.exe后再试  8、VISTA系统中请关闭UAC后以XP兼容模式来运行setup.bat  9、使用完整版XP,避免使用精简版XP  ★评论反馈常见问题以及相关解决方法 ★  1、检查运行环境,你的系统是否是windows XP,某些游戏不支持Vista,win7。  2、下载之前阅读游戏介绍,大部游戏有配置要求,比如显卡、内存要求。如果达不到要求,经常会出现启动游戏黑屏或者画面很卡。  3、运行游戏提示“缺少d3dx9_41.dll”“Xlive.dll”等类似的.dll文件,需要安装显卡插件,下载地址:  4、运行游戏时出现[“0x0048d5fa&指令引用的“0x&内存。该内存不能为“read&]类似错误,可能是以下原因:  (1) 杀毒软件与游戏程序冲突,关闭所有杀毒软件或者防护软件。  (2) 请确定游戏解压目录为全英文。  (3) 重装微软的NET.Framework。点击进入官网下载:,&   也可在下载您需要的.NET版本  ★游戏下载中的问题★  1、怎么下载才能达到最快?请使用下载工具,比如迅雷,快车,旋风下载,推荐使用迅雷下载!  2、如果遇到文件格式是 ISO、CUE、CCD、MDS、IMG等,请用虚拟光驱运行安装游戏:【DAEMON Tools下载地址:&】。  3、文件格式为:exe、rar、7z、zip,后三种格式可用Winrar解压!  ★硬盘版游戏安装问题收集【学习用】★  1 安装了XXX游戏,运行时说找不到d2d9.dll文件。  请安装微软DirectX 9以上版本。  微软Direct X主页:/windows/directx/default.aspx  记得按你系统的语言来选择适当的程序。例如中文版应该选择这个页面下载:  Direct X 9中文下载页面,也可以到中下载。  2 下载了某个游戏,但只是一堆XXXXX.r00,XXXXX.r01,……的文件。  请使用WINRAR等RAR解压软件解压缩。只需选其中任何一个开始解压都可以自动解压出来,然后点击文件夹内的exe程序进行安装。  WINRAR可在&下载。  3 网上下载了某个游戏,下载完(解压后)只是一个ISO,CUE,BIN文件,该如何打开?  请使用虚拟光驱虚拟使用。虚拟光驱软件推荐使用  Daemon Tools 3.47以上版本。    4 安装时出现“软件安装端口不支持”  这个问题主要出现在WIN98、ME等系统安装部分软件时会出现。是由于微软新安装程序(调用xxx.msi的安装文件)在这个系统不支持而出现的。可以安装最新版的Microsoft Installer:文件名为instmsi.exe 和 Instmsiw.exe 的程序。  下载地址在微软或搜索以上两个文件名即可(大型软件安装盘上面一般都有附的,例如OFFICE 2000等)。  5 安装某游戏,说要注册码,应该到哪里找?  首先,建议使用正版软件,那么注册码看说明书。如果是“来历不明”的软件,请看看包装袋上面有无,然后找寻软件安装盘里面的readme.txt,安装说明.txt,……等说明文件,大多数游戏需要注册码的我们都会在下载页面上作出详细  的说明并附上注册码希望玩家能仔细观察。另外也可以找相应的xxxxx.NFO文件(NFO文件请安装最新版的DAMN_NFOViewer来查看,也可以直接用记事本打开。),或者寻找叫“crack”的文件夹,在里面找答案。如果还是找不到,可以上  网搜索。  最后,如果还是不行,那么你还是去买个正版吧。  6 繁体游戏乱码。  WIN98,ME可以使用MAGICWIN,RICHWIN等软件。  WIN2000,XP以上可以使用“化繁为简”或其他相应的内码转换软件。  7 乱码,或运行后无反应。(例如6日文版)  98,ME同上  XP请使用微软Microsoft AppLocale。  8 有没有把日文翻译成中文的工具。  无,死心吧!唯一的工具就是你的脑袋。  当然,某些游戏的死忠网站会有可能发布这个游戏的非官方中文补丁。  9 游戏中贴图错误。  首先见问题1,看你使用的DirectX是否达到游戏要求的版本。  其次如果是新游戏请更新你的显卡驱程,或检查你显卡是否属于兼容型号。然后到官方网站寻找这个游戏的最新补丁。  如果是旧游戏,那么请搜索一下这个游戏的相关讨论,寻找合适版本的显卡驱程或补丁。  10 游戏中途退出/非法操作或死机。  这个问题嘛……程序BUG,硬件兼容问题,软件冲突问题都有可能,所以先检查一下自己的系统然后连同自己的配置,游戏版本,发出来提问。切忌直接问“我玩XXX突然死机了,怎么办。”这样没有人懂答你的!  另外游戏中尽量不要使用Alt+Tab切换到桌面。  11 使用了XXX修改器后,游戏玩不了/读不了存档……  首先,要完全享受游戏乐趣,还是建议不要修改。  其次,修改游戏之前请做好备份工作。使用修改器请注意核对是否跟游戏的版本一致。  再次,不懂基本原理,还是不要随便学人修改。  然后,修改时切忌贪得无厌,过度修改。  最后,发生这种情况,请默哀,重装游戏。  12 某某游戏存不了存档  这个主要来自以下几个问题:  1 安装问题,部分制作不良的D版,可能压缩时会去掉SAVE文件夹或安装时会略去SAVE文件夹的创建环节,以致无法存档。这个要找会游戏的安装目录或默认存储目录,然后建立相应的SAVE或SAV文件夹。例如某D版伊苏6和英雄传说6。  2 游戏本身规则设置问题,我不想在这讨论随时存档和定点存档的差别,但有的游戏是采用定点存档的方式,即需要在固定储存点里面才可以存档,或剧情进入到某个章节才可以的。这时不用着急,找到储存点再存档。  3 游戏软件程序BUG的问题,这个需要找相应补丁了。  4 最容易忽略的,硬盘空间不足或写保护文件问题。特别是部分直接从光盘拷贝的游戏,可能原来存档默认已经写保护了,所以无法覆盖改写。文件―》属性,把写保护去掉即可。  13 安装时无法装载DLL文件  有时候提示某些DLL文件装载错误的,在安全模式下可以装。  14 再说说关于繁体游戏乱码  关于简体操作系统玩儿繁体中文游戏看到乱码的问题,现在微软专门出了一个补丁程序:AppLocale,搜索一下这个软件就好了,一切游戏程序通用,非常方便,当然有些游戏中我们帮您打入了乱码修正大师会提供选项给您选择,如果没  有的话也可以自行去下载来进行解码。  15 关于很多游戏STARFORCE的破解  starforce,在游侠网可以下载到一个专克starforce的工具,自己去搜索下载一下,也是一种通用的方式  16 XP系统如何玩DOS的老游戏?  安装一个叫DOSBOX的软件,最新版本为0.73。可以在下载。  基本使用方法是:  1 建立一个摆的文件夹,我这里举例为:e:\dosgame,把游戏放在里面。  2 进入DOSBOX后,输入命令:mount c &e:/dosgame&  或者在DOSBOX CONF文件里面[Autoexec]下面键入mount c &e:/dosgame&,这样就不用每次进行设置了。  3 输入命令:c: 进入游戏目录,运行游戏。
飞翔声明:飞翔网登载此文出于传递更多信息之目的,并不意味着赞同其观点或证实其描述。
评论:0 次
阅读本文后您有什么感想? 已有 0 人给出评价!安卓存储工具软件大全
很多数据当前用不到不代表就没有用,所以应当存储起来,用的时候拿出来直接使用是非常轻松快捷的!下面小编为大家推荐几款关于安卓存储的工具类应用,这些应用的大小都不是很大,但功能却是非常的不错,能够充分满足大家的存储需求,赶紧下载试试吧!
简介:忆存储应用软件是一个首款智能存储管理平台,开启智能存储新时代。主要适用于安卓系统,此应用拥有热门推荐、备份、智能管理文件等功能。方便用户对手
简介:oppo云服务是一款由OPPO官方推出的云储存服务,大家可以随时将文件、视频等各内容存储到云空间,节省内存,而且永久保存,不会丢失,需要的朋
简介:华硕网络存储(WebStorage)是一款网络存储应用,华硕网络存储的功能很简单,就是往华硕的服务器上传文件。现在大厂都在涉足云存储,有些后
大小:768KB
简介:存储版计算器是一款方便并且很简洁的计算器,自带记忆功能,可以很有效的存储计算的结果。无广告、无插件、完全免费。让您摆脱记忆结果的烦恼。 存储...
大小:11MB
简介:酷盘(Kanbox)是一款十分好用的在线存储软件。该软件界面简洁,但功能却十分全面。在手机上安装酷盘客户端后,您就可随时在PC、网络及手机之...
大小:215KB
简介:OverDisk是一款能够管理你的手机存储空间的系统应用。系统备份,文件传输,笔记本及平板设备产品线等元素有机的结合在了一起,而且联系非常紧...
简介:无限相册app是一款能让手机内存平白扩充的软件。非常实用。又是因为内存的问题,朋友们都不得不删去很多珍贵的照片,但是它是同步云盘的,所以想存...
简介:存储空间清理是一款存储空间清理工具应用。这个应用的界面给人一种质朴实在的感觉,清理起空文件夹也挺干练,高级功能需付费,一瓶水的价格挺好接受。...
大小:11MB
简介:pCloud网盘是一款来自保加利亚的网盘应用。这个网盘的初始大小10G,支持普通 http 链接离线下载,号称不限速,实际测试能达到 500...
简介:大家期盼已久的360云盘企业版正式上线啦,还没下载的小伙伴可以看过来,小编把免费版带给大家,为企业办公提高极大的便利哦,千万不要错过啦。 3...
简介:360云盘企业版最新版拥有强大的文件、日志、组织架构、用户等管理功能,还能为企业定制专属logo哦,让您的企业形象更加深入人心。 360云盘...
简介:思维点藏是一款用于离线保存网页的应用。该应用界面清爽,可设置悬浮窗在想保存的内容页面进行点击操作后保存下来,对知识的整合归纳有帮助。在没有网...
大小:11MB
简介:亚马逊照片Amazon Photos是一款简单实用的照片储存应用。这个应用不知道多少人会用,一般都 dropbox 或者 google 自家...
大小:18MB
简介:VPAN2代是一款由江苏省苏州四维空间智能科技有限公司推出的云端网络存储应用。这个应用可以让用户控制远程下载视频和音乐资源,功能相当全面,感...
简介:照片储物柜是一款功能强大的照片存储工具,为你提供简单快捷的照片存储服务,本款软件虽然简单但功能却不简单,安全、方便的为你存储你的手机图片, ...
简介:无线手机U盘是一款实用性的手机存储工具,在电脑PC端轻松浏览和管理手机上SD的文件,让手机化身一款无线U盘,轻松管理照片和文件, 从此不再需...
简介:迅雷手机U盘是一款手机文件保存管理应用。该应用可以通过直插或无线方式访问迅雷U盘,将手机里的文件转移到U盘里,或者取出U盘里的文件资料,还可...
大小:932KB
简介:DiskInfo PRO是一款可以查看存储详细信息的软件。这个应用能看的信息很详细,非常的方便!这年头手机里总是些乱七八糟的文件不知道干嘛的...
简介:InstaSave是一款和ins功能差不多的手机软件,支持快速的保存图片,超强大的图片存储空间,非常高的用户体验度你还在等什么?快来下载吧!...
简介:EZ音乐播放器是一款文件夹模式的音乐播放器。本款软件支持云端存储与本地存储两种模式让你随时随地的收藏最好听的音乐喜欢的用户快来下载吧! EZ...
大小:471KB
简介:外部存储应用LetsGoApp是一款可以将应用移动到外部存储并通过此应用启用的工具应用。这个应用使用起来比较方便并可以在多设备间切换使用。 ...
简介:360云盘是一款由360官方打造的云存储软件,用户通过我们的软件可以便捷的将自己的手机变成U盘,便于自己记录数据,且不会丢失,非常的实用!有...
简介:乐视云盘不限速版是一款非常实用的云盘工具,不限制下载速度让你可以下载更多的资源,海量的云存储空间让你更好的学习与办公,喜欢的用户快来下载吧!...
简介:360云盘企业版破解版带给大家,无需花费即可使用哦,内置海量个人空间、公共空间,无论是存储个人文件,还是企业文件都可以哦,实现一键快速转存,...
简介:360云盘企业版2017为广大员工实现在线云办公新体验,极速的上传下载功能提高办公效率,方便快捷的文件共享、文件在线播放值得你体验。 360...
简介:百度云网盘三星定制版是一款文件备份软件,相册、短信等各事项,只要你愿意,我们会为你永久保存,非常的便捷实用!赶快来试试吧! 百度云网盘三星定...
大小:21MB
简介:见证是一款由浙江省杭州安存网络科技有限公司推出的民用证据类软件。这个应用提供的数据可以直接存储起来,享受与支付宝同安全级,充分保护用户数据的...
简介:Seafile 是一款开源的网盘存储工具应用。这个应用的可以用来架私有云,有自动同步,还提供文件历史版本功能,感兴趣的朋友可以试一试! Se...
简介:微云盘是一款专注于文件存储备份的辅助工具应用。这个应用提供的文件处理功能强大,能够为你提供跨平台的文件存储、备份、同步、下载和分享服务,方便...
大小:43MB
简介:海康智存是一款多功能的智能存储管理工具应用。这个存储管理工具的功能还是相当给力的,能够对文件进行各种管理操作,并且还自带音视频播放功能,方便...
简介:SSD Boost是一款提高手机存储速度的工具应用。这个应用看起来很神啊,斗胆测试了一下,手机还活着。有用户提到启用后感觉更省电了,能够优化...
简介:360云盘企业版专供企业使用,方便企业人员及时存储办公文件,做到安全备份,支持一键导入,有需要的用户快来下载吧。 360云盘企业版功能介绍 ...
简介:LINE DECO是一款图片壁纸储存应用。该应用包含了3000款图标和壁纸,无法抵挡的萌系风格,以LINE中卡通人物为主角的系统美化应用,可...
大小:21MB
简介:扫描全能王,提供文档扫描、存储、管理、分享、交流、协作、同步的一体化解决方案。将手机变成随身携带的扫描仪、传真机、PDF转换器、Text文本...
简介:Amazon Cloud Drive 是您存储所有数字内容的好地方。Cloud Drive 提供移动应用,您可以从任何计算机上安全访问,并且...
简介:Periscope存储分析是一款有一些动态效果的存储工具应用。如果手机存储不够了,这东西应该能帮上忙,这种类型的最大优点就是直观,功能实用,...
简介:移动云盘是一款实用的云数据存储管理工具,本款软件简单实用实时的为你提供服务,让你随时随地的享受最好的服务,软件操作简单让你随时随地的查看分享...
简介:吾爱免流云流量平台是一款免流量的手机app神器,把流量存起来,随时随地都能提取哦,想要立即体验吗,那就快来游迅网下载吧! 吾爱免流一键搭建脚...
大小:13MB
简介:FolderSync Lite是一款简单实用的云端存储工具应用。这个应用是专门给用户进行云端存储的,而且支持不少服务的同步应用,简单易用,体...
简介:百度云企业版是一款大存储的云端存储工具,独立是云盘系统帮助你更简单的使用百度云,需要的用户快来下载吧! 百度云企业版软件特色: 【超强的文档...
大小:13MB
简介:百度云OPPO手机定制版是一款专为OPPO手机打造的百度云专用存储工具。这个应用是专门进行了系统级别的适配定制,不闪退,更稳定。百度云面向所...
大小:20MB
简介:ASUS 云存储是一款受到用户一致好评的实用性的手机云存储软件,件你的手机文件存储到云端大大洁身自己的手机内存,只要提取码轻松即可提取自己的...
简介:巨能传是一种便携式闪存存储设备,让您的数字媒体内容流传输(如音频,视频,图片,文字等)到你的手机设备。 为自己的无线网络,巨能传配备高容量锂...
简介:够快云库是一款基于云存储的团队协作性文件管理平台、移动办公系统。团队成员可以同步共享资料,即时沟通交流,便捷移动办公,从而实现团队的100%...
简介:内存扫描器是一款手机存储分区检测的独特应用。该应用列出了手机设备上的所有分区和所有存储挂载。能够显示磁盘使用情况和非常详细的分区和存储信息,...
简介:手由宝是一款简单实用的视频资源快速存储的工具,本款软件的界面简洁实时的为你提供便捷的服务,让你轻松的看视频、存视频不耗费流量,和手由宝互传文...
大小:21MB
简介:SSKCloud是一款配合SSK家存储硬件设备的工具应用。这个应用可以通过Wi-Fi扩充您的智能手机、平板电脑和电脑的存储。 SSKClou...
简介:无线随手存盘是一款简单实用的手机内存管理的手机服务软件,简单的操作帮助你随手存储自己的信息,便捷的文件管理工具,帮助你条理清晰的管理自己的手...
大小:19MB
简介:浙师云盘是一款专业的手机网盘辅助工具应用。通过浙师云盘可以实现电脑、手机、平板等多平台终端设备数据互通,可以用于存储文档、图片、视频等各种资...
大小:42MB
简介:115云盘是一款功能强大的云端储存软件,用户通过我们的软件能够便捷的储存重要的信息资料,保护信息安全,不用担心数据的丢失,赶快来试试吧! 1...
大小:19MB
简介:云存储工具是一款多功能的安全性高的云存储工具。这个应用的功能看名字就知道是做什么的了,能够让你在线存储、同步和共享机密文件,操作简单,使用方...
简介:手机存储不够用,不妨试试这款杏娱网盘,容量大,完全免费使用,用户随时可以进行全盘搜索,实用性强,快来下载吧。 杏娱网盘介绍 全球最多用户的云...
简介:杏娱网盘是款与众不同的网盘工具,不仅可以帮你存储各种文件,同时内置海量影视剧资源,方便大家随时观看。 杏娱网盘软件特色 【相册自动备份】便捷...
简介:云创网盘是一款专属定制的网盘系统,为用户提供专业、安全的云端服务,超大存储量,快速传输给你最便捷的服务,需要的用户快来下载试试吧! 云创网盘...
简介:匣是一款专门用来储存账号以及密码的工具应用。这个应用的功能比较简单,除了存储账号以及密码的功能以外就没有其他的了,功能很是纯粹,方便快捷,对...
大小:13MB
简介:百百度云联想定制版是一款国内最受欢迎、最专业、最稳定的云端数据存储平台。这个应用里面拥有2T永久免费空间、群组资源分享、视频照片文件快速备份...
大小:12MB
简介:云手机是一款帮助用户把文件储存到云端的手机应用。该应用为用户提供一定的存储空间,帮助您解放手机内存,为您的手机带来更好的效能。快来下载吧! ...
简介:DM无线存储应用软件是一款android手机/无线存储设备管理工具,能够帮助您轻松便捷地批量管理手机、无线存储设备中的图片、音 乐、视频、文...
简介:由360推出的360云盘企业版更加专业,功能更加强大,超大的免费存储空间、文件自动同步等,为企业办公人员带来极致的办公体验。 360云盘企业...
大小:17MB
简介:安全云存储(Tresorit)是一款以安全为主的云存储服务应用。该应用唯一的毛病就是空间稍微有那么一点小,那么应该可以用来放一些真正重要的文...
大小:21MB
简介:微软云盘应用软件是一款可以提供储存档案的位置,让您几乎可从任何装置存取您的档案。现在透过 SkyDrive for Android,您可以随...
简介:OneNote是一款帮助你轻松办公学习的笔记云存储软件。您所有的笔记都集中在一个地方,方便您随时随地存取。 OneNote 是数位笔记本,可...
大小:723KB
简介:华数云盘是一款云存储网盘服务应用。该应用基于华数强大的云存储集群及云计算技术,为用户提供存储容量大、免费、安全、便捷、稳定的跨平台文件存储、...
简介:wifi传输器是一款专为提高无线存储产品的易用性而开发的应用软件。有了此款软件配合使用wifi传输器,可轻松玩转wifi,让您体验无线新感觉...
大小:15MB
简介:云端硬盘是一款云端存储软件,本款软件帮助你轻松的存储自己的文件,你可以分享给你自己的伙伴,可以随意的访问,喜欢的用户快来下载吧! 你可以存放...
大小:20KB
简介:处理外部存储模块HandleExternalStorage是一款可以用来让插了卡的设备中也能存取数据的Xposed模块应用。这个应用体积非常...
大小:22MB
简介:Naver网盘是一款在线储存工具软件,在线存储,轻松便捷,永不遗失,超大内存空间,让你想存就存。随时随地在线浏览,让你丢弃U盘,硬盘,让你的...
大小:21MB
简介:个人云是一款个人云端存储管理软件,为了扩充你的手机空间,你需要将自己的一部分文件转移出来,把它们存储到哪里呢?下载个人云你的私人云端管理工具...
大小:12MB
简介:Copy网盘是一款最近在线存储领域的网盘应用。虽然这款应用刚出来不久,但是东西的质量还是相当不错的! Copy网盘是一款在线存储应用,目前支...
简介:创意云盘是一款手机存储软件,我们的软件为你提供一个庞大的存储空间,而且我们的上传速度也极快,保证让你满意!有兴趣的快来下载吧! 创意云盘向用...
简介:驿邮取件宝是一款专为快件存储打造的手机软件,用户通过我们的软件能够更加便捷的查看快递信息,凭借二维码取件,非常的便利!有需要的快来试试吧! ...
简介:越来越多的用户开始选择使用云盘存储备份,小编这里为你带来一款专业的360云盘企业版,专供企业用户使用,让办公更加效率。 360云盘企业版介绍...
简介:UMS Iterface是一款大容量的存储配置工具应用。这个应用能够方便用户配置相关的存储信息,方便快捷,不过需要有root权限才行,操作起...
简介:还在为没有好用的网盘而烦恼吗,现在下载杏娱网盘,随时看热门电影电视剧,支持高清播放哦,本次为大家带来的会员破解版,不需要再花钱了。 杏娱网盘...
简介:工作文件夹是一款微软提供的存储文件并加密的应用。这个应用比较适合商务人士,另外图标可能和OneNote的相比有点像! 工作文件夹是一个位置,...
简介:全携通是一款强大实用的手机办公云盘存储软件。该应用界面简洁,操作简单,功能实用,能帮助企业用户方便安全快捷的将资料存储在云端,随时随地查看文...
简介:加密存储 Eds是一款专注于加密存储的工具应用。这个应用的加密级别非常高,设置也有点小复杂,只是存个小电影就没必要用了 ! 有了 EDS 你...
简介:百度云是一款实用的文件云存储工具,海量空间等着来填满,2T永久免费空间。百度云可以创建群组,一人分享,全群共享,支持分享本地文件给好友,让你...
简介:百度网盘三星定制版是一款由三星与百度网盘合作打造的一项云存储服务工具应用。看看三星的待遇,就是不一样,至于好不好用,三星用户可以试一试嘛! ...
合集推荐Collections
CopyRight2004年-年
游迅网 All Rights Reserved
备案编号:沪ICP备号-9Java游戏服务器成长之路——弱联网游戏篇(源码分析) - CSDN博客
Java游戏服务器成长之路——弱联网游戏篇(源码分析)
前段时间由于公司的一款弱联网游戏急着上线,没能及时分享,现在基本做的差不多,剩下的就是测试阶段了(本来说元旦来分享一下服务器技术的)。公司的这款游戏已经上线一年多了,在我来之前一直都是单机版本,由于人民群众的力量太强大,各种内购破解,刷体力,刷金币,刷钻石版本的出现,公司才决定将这款游戏转型为弱联网游戏,压制百分之八十的破解用户(毕竟原则上还是属于单机游戏,不可能做到百分之百的防破解),招了我这一个服务器来进行后台的开发。什么是弱联网游戏?在这之前我也没有做过弱联网游戏的服务器,但是按照我对策划对我提出的需求的理解,就是游戏的大部分逻辑运算都是在移动端本地完成,而服务器要做的就是登录、支付验证、游戏存档读档的工作,这相对于我在上家公司做的ARPG那种强联网游戏要简单多了,那款ARPG就是所有游戏产出,逻辑运算都是在服务器端完成,服务器要完成大部分的游戏运算,而我做的这款弱联网游戏,只需要简简单单的登录、验证、读取和存储。这一类的游戏,做的最火的,就是腾讯早期手游中的《全民消消乐》《节奏大师》《天天飞车》(天天飞车后来加的实时竞赛应该还是强联网的实时数据)等,这类游戏中,服务器就只需要负责游戏数据存储和一些简单的社交功能,例如qq好友送红心送体力的等。
公司招聘我进来做服务器开发其实是为了两个项目,一个是这款单机转弱联网的游戏,另一款是公司准备拿来发家致富的SLG——战争策略游戏。从入职到现在,我一直是在支持弱联网游戏的开发,到现在,基本上这款游戏也算是差不多了,这款游戏的目前版本仍然基本属于单机,到年后会加上竞技场功能,到时候可能就会需要实时的数据交互了,现在就先来分享一下目前这个版本开发的过程。
要开发一个后台系统,首先要考虑的就是架构了,系统的高效稳定性,可扩展性。在游戏开发中,我认为后台服务器无非负责几个大得模块:
1. 网络通信
2. 逻辑处理
3. 数据存储
4. 游戏安全
首先从需求分析入手,我在这款弱联网游戏中,后端需要做的事情就是,登录,支付验证,数据存储,数据读取,再加上一些简单的逻辑判断,第一眼看去,并没有任何难点,我就分别从以上几点一一介绍
弱联网游戏,基本上来说,最简单直接的,就是使用http短连接来进行网络层的通信,那么我又用什么来做http服务器呢,servlet还是springmvc,还是其他框架。因为之前做的ARPG用的一款nio框架——mina,然后对比servlet和springmvc的bio(实质上,springmvc只是层层封装servlet后的框架,它的本质原理还是servlet),个人还是觉得,作为需要处理大量高并发请求的业务需求来说,还是nio框架更适合,然而,我了解到netty又是比mina更好一点的框架,于是我选择了netty,然后自己写了demo测试,发现netty的处理性能确实是很可观的,netty是一个异步的,事件驱动的网络编程框架,使用netty可以快速开发出可维护的,高性能、高扩展能力的协议服务及其客户端应用。netty使用起来基本上就是傻瓜式的,它很好的封装了java的nio api。我也是刚刚接触这款网络通信框架,为此我还买了《Netty权威指南》,想系统的多了解下这款框架,以下几点,就是我使用netty作为网络层的理由:
1. netty的通信机制就是它本身最大的优势,nio的通信机制无论是可靠性还是吞吐量都是优于bio的。
2. netty使用自建的buffer API,而不是使用NIO的ByteBuffer来代表一个连续的字节序列。与ByteBuffer相比这种方式拥有明显的优势。netty使用新的buffer类型ChannelBuffer,ChannelBuffer被设计为一个可从底层解决ByteBuffer问题(netty的ByteBuf的使用跟C语言中使用对象一样,需要手动malloc和release,否则可能出现内存泄露,昨天遇到这个问题我都傻眼了,后来才知道,原来netty的ByteBuf是需要手动管理内存的,它不受java的gc机制影响,这点设定有点返璞归真的感觉!)。
3. netty也提供了多种编码解码类,可以支持Google的Protobuffer,Facebook的Trift,JBoss的Marshalling以及MessagePack等编解码框架,我记得用mina的时候,当时看老大写的编解码的类,貌似是自己写protobuffer编解码工具的,mina并没有支持protobuffer。这些编解码框架的出现就是解决Java序列化后的一些缺陷。
4. netty不仅能进行TCP/UDP开发,更是支持Http开发,netty的api中就有支持http开发的类,以及http请求响应的编解码工具,真的可谓是人性化,我使用的就是这些工具,除此之外,netty更是支持WebSocket协议的开发,还记得之前我自己试着写过mina的WebSocket通信,我得根据WebSocket的握手协议自己来写消息编解码机制,虽然最终也写出来了,但是当我听说netty的api本身就能支持WebSocket协议开发的时候,我得内心几乎是崩溃的,为什么当初不用netty呢?
5. 另外,netty还有处理TCP粘包拆包的工具类!
可能对于netty的理解还是太浅,不过以上几个优势就让我觉得,我可以使用这款框架。实时也证明,它确实很高效很稳定的。
废话不多说,以下就贴出我使用netty作为Http通信的核心类:
public class HttpServer {
public static Logger log = LoggerFactory.getLogger(HttpServer.class);
public static HttpS
public static P
public static int
private NioEventLoopGroup bossGroup = new NioEventLoopGroup();
private NioEventLoopGroup workGroup = new NioEventLoopGroup();
public static ThreadPoolTaskExecutor handleTaskE
private HttpServer() {
*: initThreadPool
*: 初始化线程池
public void initThreadPool() {
handleTaskExecutor = new ThreadPoolTaskExecutor();
handleTaskExecutor.setQueueCapacity(Integer.parseInt(p
.getProperty("handleTaskQueueCapacity")));
handleTaskExecutor.setCorePoolSize(Integer.parseInt(p
.getProperty("handleTaskCorePoolSize")));
handleTaskExecutor.setMaxPoolSize(Integer.parseInt(p
.getProperty("handleTaskMaxPoolSize")));
handleTaskExecutor.setKeepAliveSeconds(Integer.parseInt(p
.getProperty("handleTaskKeepAliveSeconds")));
handleTaskExecutor.initialize();
public static HttpServer getInstance() {
if (inst == null) {
inst = new HttpServer();
inst.initData();
inst.initThreadPool();
public void initData() {
p = readProperties();
port = Integer.parseInt(p.getProperty("port"));
} catch (IOException e) {
log.error("socket配置文件读取错误");
e.printStackTrace();
public void start() {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workGroup);
bootstrap.channel(NioServerSocketChannel.class);
bootstrap.childHandler(new ChannelInitializer&SocketChannel&() {
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("decoder", new HttpRequestDecoder());
pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
pipeline.addLast("encoder", new HttpResponseEncoder());
pipeline.addLast("http-chunked", new ChunkedWriteHandler());
pipeline.addLast("handler", new HttpServerHandler());
("端口{}已绑定", port);
bootstrap.bind(port);
public void shut() {
workGroup.shutdownGracefully();
workGroup.shutdownGracefully();
("端口{}已解绑", port);
* 读配置socket文件
* IOException
protected Properties readProperties() throws IOException {
Properties p = new Properties();
InputStream in = HttpServer.class
.getResourceAsStream("/net.properties");
Reader r = new InputStreamReader(in, Charset.forName("UTF-8"));
p.load(r);
in.close();
网络层,除了网络通信,还有就是数据传输协议了,服务器跟客户端怎么通信,传什么,怎么传。跟前端商议最终还是穿json格式的数据,前面说到了netty的编解码工具的使用,下面贴出消息处理类:
public class HttpServerHandlerImp {
private static Logger log = LoggerFactory
.getLogger(HttpServerHandlerImp.class);
public static String DATA = "data";
public static String PAY = "pay";
public static String TIME = "time";
public static String AWARD = "award";
public static volatile boolean ENCRIPT_DECRIPT = true;
public void channelRead(final ChannelHandlerContext ctx, final Object msg)
throws Exception {
HttpServer.handleTaskExecutor.execute(new Runnable() {
public void run() {
if (!GameServer.shutdown) {
DefaultFullHttpRequest req = (DefaultFullHttpRequest)
if (req.getMethod() == HttpMethod.GET) {
if (req.getMethod() == HttpMethod.POST) {
HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(
new DefaultHttpDataFactory(false), req);
InterfaceHttpData postGameData = decoder
.getBodyHttpData(DATA);
InterfaceHttpData postPayData = decoder
.getBodyHttpData(PAY);
InterfaceHttpData postTimeData = decoder
.getBodyHttpData(TIME);
InterfaceHttpData postAwardData = decoder
.getBodyHttpData(AWARD);
if (postGameData != null) {
String val = ((Attribute) postGameData)
.getValue();
val = postMsgFilter(val);
Router.getInstance().route(val, ctx);
} else if (postPayData != null) {
String val = ((Attribute) postPayData)
.getValue();
val = postMsgFilter(val);
Router.getInstance().queryPay(val, ctx);
} else if (postTimeData != null) {
String val = ((Attribute) postTimeData)
.getValue();
val = postMsgFilter(val);
Router.getInstance().queryTime(val, ctx);
} else if (postAwardData != null) {
String val = ((Attribute) postAwardData)
.getValue();
val = postMsgFilter(val);
Router.getInstance().awardOperate(val, ctx);
} catch (Exception e) {
e.printStackTrace();
JSONObject jsonObject = new JSONObject();
jsonObject.put("errMsg", "server closed");
writeJSON(ctx, jsonObject);
private String postMsgFilter(String val)
throws UnsupportedEncodingException {
val = val.contains("%") ? URLDecoder.decode(val, "UTF-8") :
String valTmp =
val = ENCRIPT_DECRIPT ? XXTeaCoder.decryptBase64StringToString(val,
XXTeaCoder.key) :
if (Constants.MSG_LOG_DEBUG) {
if (val == null) {
val = valT
("server received : {}", val);
public static void writeJSON(ChannelHandlerContext ctx,
HttpResponseStatus status, Object msg) {
String sentMsg = JsonUtils.objectToJson(msg);
if (Constants.MSG_LOG_DEBUG) {
("server sent : {}", sentMsg);
sentMsg = ENCRIPT_DECRIPT ? XXTeaCoder.encryptToBase64String(sentMsg,
XXTeaCoder.key) : sentM
writeJSON(ctx, status,
Unpooled.copiedBuffer(sentMsg, CharsetUtil.UTF_8));
ctx.flush();
public static void writeJSON(ChannelHandlerContext ctx, Object msg) {
String sentMsg = JsonUtils.objectToJson(msg);
if (Constants.MSG_LOG_DEBUG) {
("server sent : {}", sentMsg);
sentMsg = ENCRIPT_DECRIPT ? XXTeaCoder.encryptToBase64String(sentMsg,
XXTeaCoder.key) : sentM
writeJSON(ctx, HttpResponseStatus.OK,
Unpooled.copiedBuffer(sentMsg, CharsetUtil.UTF_8));
ctx.flush();
private static void writeJSON(ChannelHandlerContext ctx,
HttpResponseStatus status, ByteBuf content/* , boolean isKeepAlive */) {
if (ctx.channel().isWritable()) {
FullHttpResponse msg = null;
if (content != null) {
msg = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status,
msg.headers().set(HttpHeaders.Names.CONTENT_TYPE,
"application/ charset=utf-8");
msg = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status);
if (msg.content() != null) {
msg.headers().set(HttpHeaders.Names.CONTENT_LENGTH,
msg.content().readableBytes());
ctx.write(msg).addListener(ChannelFutureListener.CLOSE);
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
public void messageReceived(ChannelHandlerContext ctx, FullHttpRequest msg)
throws Exception {
以上代码,由于最后商议所有接口都通过post实现,所以get请求部分代码全都注释掉了。解析json数据使用的是gson解析,因为gson是可以直接解析为JavaBean的,这一点是非常爽的。工具类中代码如下:
* 将json转换成bean对象
public static Object jsonToBean(String jsonStr, Class&?& cl) {
Object obj = null;
if (gson != null) {
obj = gson.fromJson(jsonStr, cl);
* 将对象转换成json格式
public static String objectToJson(Object ts) {
String jsonStr = null;
if (gson != null) {
jsonStr = gson.toJson(ts);
return jsonS
在这款弱联网游戏中,一个是登录逻辑,游戏有一个管理服务器,管理其他的逻辑服务器(考虑到下版本开竞技场会有分服选服),登录和支付都是在管理服务器造成的,其他接口才会通过管理服务器上获得的逻辑服务器IP去完成其他交互,在逻辑服务器上基本上也不会有什么逻辑处理,基本上是接到数据就进行解析,然后就进行存储或缓存。唯一有一点逻辑处理的就是,例如金币钻石减少到负数了,就把数据置零。逻辑上,netty接收到请求之后,就进入我的一个核心处理类,Router,由Router再将消息分发到各个功能模块。Router代码如下:
*: 路由分发
public void route(String msg, ChannelHandlerContext ctx) {
GameData data = null;
data = (GameData) JsonUtils.jsonToBean(msg, GameData.class);
} catch (Exception e) {
logger.error("gameData的json格式错误,{}", msg);
e.printStackTrace();
HttpServerHandler.writeJSON(ctx, HttpResponseStatus.NOT_ACCEPTABLE,
new BaseResp(1));
if (data.getUserID() == null) {
logger.error("存放/回档错误,uid为空");
HttpServerHandler.writeJSON(ctx, new BaseResp(1));
long junZhuId = data.getUserID() * 1000 + GameInit.serverId;
/** 回档 **/
if (JSONObject.fromObject(msg).keySet().size() == 1) {
GameData ret = junZhuMgr.getMainInfo(junZhuId);
ret.setTime(new Date().getTime());
ret.setPay(getPaySum(data.getUserID()));
HttpServerHandler.writeJSON(ctx, ret);
/** 存档 **/
if (data.getDiamond() != null) {
if (!junZhuMgr.setDiamond(junZhuId, data)) {
HttpServerHandler.writeJSON(ctx, new BaseResp(1));
JunZhu junZhu = HibernateUtil.find(JunZhu.class, junZhuId);
HttpServerHandler.writeJSON(ctx, new BaseResp(junZhu.coin,
junZhu.diamond, 0));
GameData则是用于发送接收的消息Bean
在这样的游戏中,逻辑运算基本由客户端操作了,因此游戏数据的持久化才是服务器的重点,必须要保证游戏的数据的完整性。数据库上,我选择了Mysql,事实上,我认为MongoDB更适合这类数据的存储,因为本身数据库就可以完全按照json格式原样存储到数据库中,但由于项目预期紧,我也不敢去尝试我没尝试过的方式,然而选择mysql,也不是什么坏事,mysql在游戏数据的处理也是相当给力,mongo虽好,却没有关系型数据库的事务管理。根据策划的需求,我将游戏数据分析完了之后,就基本理清了数据库表结构,在项目中我使用了Hibernate4作为ORM框架,相对于前面的版本,Hibernate4有一个很爽的功能,就是在JavaBean中添加一些注解,就能在构建Hibernate的session的时候,自动在数据库创建表,这样使得开发效率快了好几倍,Hibernate本身就已经够爽了,我认为至今没有什么ORM框架能跟它比,以前也用过MyBatis,个人感觉MyBatis更适合那种需要手动写很复杂的sql才用的,每一个查询都要写sql,在Hibernate中,简简单单几行代码,就能完成一个查询,一下贴出Hibernate工具类:
public class HibernateUtil {
public static boolean showMCHitLog = false;
public static Logger log = LoggerFactory.getLogger(HibernateUtil.class);
public static Map&Class&?&, String& beanKeyMap = new HashMap&Class&?&, String&();
private static SessionFactory sessionF
public static void init() {
sessionFactory = buildSessionFactory();
public static SessionFactory getSessionFactory() {
return sessionF
public static Throwable insert(Object o) {
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
session.save(o);
session.getTransaction().commit();
} catch (Throwable e) {
log.error("0要insert的数据{}", o == null ? "null" : JSONObject
.fromObject(o).toString());
log.error("0保存出错", e);
session.getTransaction().rollback();
return null;
* FIXME 不要这样返回异常,没人会关系返回的异常。
public static Throwable save(Object o) {
Session session = sessionFactory.getCurrentSession();
Transaction t = session.beginTransaction();
boolean mcOk = false;
if (o instanceof MCSupport) {
MCSupport s = (MCSupport)
MC.update(o, s.getIdentifier());
mcOk = true;
session.update(o);
session.saveOrUpdate(o);
t.commit();
} catch (Throwable e) {
log.error("1要save的数据{},{}", o, o == null ? "null" : JSONObject
.fromObject(o).toString());
if (mcOk) {
log.error("MC保存成功后报错,可能是数据库条目丢失。");
log.error("1保存出错", e);
t.rollback();
return null;
public static Throwable update(Object o) {
Session session = sessionFactory.getCurrentSession();
Transaction t = session.beginTransaction();
if (o instanceof MCSupport) {
MCSupport s = (MCSupport)
MC.update(o, s.getIdentifier());
session.update(o);
session.update(o);
t.commit();
} catch (Throwable e) {
log.error("1要update的数据{},{}", o, o == null ? "null" : JSONObject
.fromObject(o).toString());
log.error("1保存出错", e);
t.rollback();
return null;
public static &T& T find(Class&T& t, long id) {
String keyField = getKeyField(t);
if (keyField == null) {
throw new RuntimeException("类型" + t + "没有标注主键");
if (!MC.cachedClass.contains(t)) {
return find(t, "where " + keyField + "=" + id, false);
T ret = MC.get(t, id);
if (ret == null) {
if (showMCHitLog)
("MC未命中{}#{}", t.getSimpleName(), id);
ret = find(t, "where " + keyField + "=" + id, false);
if (ret != null) {
if (showMCHitLog)
("DB命中{}#{}", t.getSimpleName(), id);
MC.add(ret, id);
if (showMCHitLog)
("DB未命中{}#{}", t.getSimpleName(), id);
if (showMCHitLog)
("MC命中{}#{}", t.getSimpleName(), id);
public static &T& T find(Class&T& t, String where) {
return find(t, where, true);
public static &T& T find(Class&T& t, String where, boolean checkMCControl) {
if (checkMCControl && MC.cachedClass.contains(t)) {
throw new BaseException("由MC控制的类不能直接查询DB:" + t);
Session session = sessionFactory.getCurrentSession();
Transaction tr = session.beginTransaction();
T ret = null;
String hql = "from " + t.getSimpleName() + " " +
Query query = session.createQuery(hql);
ret = (T) query.uniqueResult();
tr.commit();
} catch (Exception e) {
tr.rollback();
log.error("list fail for {} {}", t, where);
log.error("list fail", e);
* 通过指定key值来查询对应的对象
public static &T& T findByName(Class&? extends MCSupport& t, String name,
String where) {
Class&? extends MCSupport& targetClz =
String key = targetClz.getSimpleName() + ":" +
Object id = MC.getValue(key);
T ret = null;
if (id != null) {
("id find in cache");
ret = (T) find(targetClz, Long.parseLong((String) id));
ret = (T) find(targetClz, where, false);
if (ret == null) {
("no record {}, {}", key, where);
MCSupport mc = (MCSupport)
long mcId = mc.getIdentifier();
("found id from DB {}#{}", targetClz.getSimpleName(), mcId);
MC.add(key, mcId);
ret = (T) find(targetClz, mcId);
例子: where uid&100
public static &T& List&T& list(Class&T& t, String where) {
Session session = sessionFactory.getCurrentSession();
Transaction tr = session.beginTransaction();
List&T& list = Collections.EMPTY_LIST;
String hql = "from " + t.getSimpleName() + " " +
Query query = session.createQuery(hql);
list = query.list();
tr.commit();
} catch (Exception e) {
tr.rollback();
log.error("list fail for {} {}", t, where);
log.error("list fail", e);
public static SessionFactory buildSessionFactory() {
("开始构建hibernate");
String path = "classpath*:spring-conf/applicationContext.xml";
ApplicationContext ac = new FileSystemXmlApplicationContext(path);
sessionFactory = (SessionFactory) ac.getBean("sessionFactory");
("结束构建hibernate");
return sessionF
public static Throwable delete(Object o) {
if (o == null) {
return null;
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
if (o instanceof MCSupport) {
MCSupport s = (MCSupport)
MC.delete(o.getClass(), s.getIdentifier());
session.delete(o);
session.getTransaction().commit();
} catch (Throwable e) {
log.error("要删除的数据{}", o);
log.error("出错", e);
session.getTransaction().rollback();
return null;
其中HibernateUtil中也用了SpyMemcached来做一些结果集的缓存,当然项目中也有其他地方用到了Memcache来做缓存。最开始的时候,我还纠结要不要把每个玩家的整个游戏数据(GameData)缓存起来,这样读起来会更快,但是我想了想,如果我把整个游戏数据缓存起来,那么每次存档,我都要把缓存中数据取出来,把要修改的那部分数据从数据库查询出来,再进行修改,再放回去,这样的话,每次存档就会多一次数据库操作,然而再想想,整个游戏中,读档只有进游戏的时候需要,而存档是随时都需要,权衡之下,还不如不做缓存,做了缓存反而需要更多数据库的操作。
缓存部分代码如下:
* 对SpyMemcached Client的二次封装,提供常用的Get/GetBulk/Set/Delete/Incr/Decr函数的同步与异步操作封装.
* 未提供封装的函数可直接调用getClient()取出Spy的原版MemcachedClient来使用.
public class MemcachedCRUD implements DisposableBean {
private static Logger logger = LoggerFactory.getLogger(MemcachedCRUD.class);
private MemcachedClient memcachedC
private long shutdownTimeout = 2500;
private long updateTimeout = 2500;
private static MemcachedCRUD
public static MemcachedCRUD getInstance() {
if (inst == null) {
inst = new MemcachedCRUD();
public static void main(String[] args) {
MemcachedCRUD.getInstance().set("test", 0, "testVal");
for (int i = 0; i & 100; i++) {
new Thread(new Runnable() {
public void run() {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
String val = MemcachedCRUD.getInstance().get("test");
Long a = MemcachedCRUD.getInstance().&Long& get("aaa");
System.out.println(a);
System.out.println(val);
}).start();
private MemcachedCRUD() {
String cacheServer = GameInit.cfg.get("cacheServer");
if (cacheServer == null) {
cacheServer = "localhost:11211";
String host = cacheServer.split(":")[0];
int port = Integer.parseInt(cacheServer.split(":")[1]);
List&InetSocketAddress& addrs = new ArrayList&InetSocketAddress&();
addrs.add(new InetSocketAddress(host, port));
ConnectionFactoryBuilder builder = new ConnectionFactoryBuilder();
builder.setProtocol(Protocol.BINARY);
builder.setOpTimeout(1000);
builder.setDaemon(true);
builder.setOpQueueMaxBlockTime(1000);
builder.setMaxReconnectDelay(1000);
builder.setTimeoutExceptionThreshold(1998);
builder.setFailureMode(FailureMode.Retry);
builder.setHashAlg(DefaultHashAlgorithm.KETAMA_HASH);
builder.setLocatorType(Locator.CONSISTENT);
builder.setUseNagleAlgorithm(false);
memcachedClient = new MemcachedClient(builder.build(), addrs);
("Memcached at {}:{}", host, port);
} catch (IOException e) {
e.printStackTrace();
* Get方法, 转换结果类型并屏蔽异常, 仅返回Null.
public &T& T get(String key) {
return (T) memcachedClient.get(key);
} catch (RuntimeException e) {
handleException(e, key);
return null;
* 异步Set方法, 不考虑执行结果.
* expiredTime
以秒过期时间,0表示没有延迟,如果exptime大于30天,Memcached将使用它作为UNIX时间戳过期
public void set(String key, int expiredTime, Object value) {
memcachedClient.set(key, expiredTime, value);
* 安全的Set方法, 保证在updateTimeout秒内返回执行结果, 否则返回false并取消操作.
* expiredTime
以秒过期时间,0表示没有延迟,如果exptime大于30天,Memcached将使用它作为UNIX时间戳过期
public boolean safeSet(String key, int expiration, Object value) {
Future&Boolean& future = memcachedClient.set(key, expiration, value);
return future.get(updateTimeout, TimeUnit.MILLISECONDS);
} catch (Exception e) {
future.cancel(false);
return false;
* 异步 Delete方法, 不考虑执行结果.
public void delete(String key) {
memcachedClient.delete(key);
* 安全的Delete方法, 保证在updateTimeout秒内返回执行结果, 否则返回false并取消操作.
public boolean safeDelete(String key) {
Future&Boolean& future = memcachedClient.delete(key);
return future.get(updateTimeout, TimeUnit.MILLISECONDS);
} catch (Exception e) {
future.cancel(false);
return false;
首先是数据传输的安全问题:当我们完成了接口对接之后,就会考虑一个问题,当别人进行抓包之后,就能很轻松的知道服务器和客户端传输的数据格式,这样的话,不说服务器攻击,至少会有人利用这些接口做出一大批外挂,本身我们加上弱联网就是为了杜绝作弊现象,于是,我们对传输消息做了加密,先做XXTea加密,再做Base64加密,用约定好的秘钥,进行加密解密,进行消息收发。再一个就是支付验证的安全问题,现在有人能破解内购,就是利用支付之后断网,然后模拟返回结果为true,破解内购。我们做了支付验证,在完成支付之后,必须到后台查询订单状态,状态为完成才能获得购买的物品,支付我之前也是没有做过,一点点摸索的。代码就不贴了,涉及到业务。
本文章只为了记录这款弱联网游戏的后台开发历程,可能之后还会遇到很多的问题,问题都是在摸索中解决的,我还需要了解更多关于netty性能方面知识。以上代码只是项目中的部分代码,并不涉及业务部分。分享出来也是给大家一个思路,或是直接拿去用,都是可以的,因为自己踩过一些坑,所以希望将这些记录下来,下次不能踩同样的坑。到目前为止,这款游戏也经过了大概半个多月的时间,到此作为记录,作为经验分享,欢迎交流探讨。我要参与的下一款游戏是长连接的SLG,到时候我应该还会面临更多的挑战,加油!
本文已收录于以下专栏:
相关文章推荐
写在开头Java游戏服务器成长之路的系列,已经很长时间没写了,不是不想写,而是这一年,基本都是在忙别的了,今天特地挤出时间,对我的2016年,做一个不留遗憾的总结。2016的事件不知不觉,又到了春节抢...
Java服务器开发的个人感悟
有很多想学习游戏服务器端编程的同学,可能会由于学校没有相应课程,或者没有一个具体的学习思路,导致中途放弃,与游戏服务器端编程擦肩而过,错失踏进游戏服务器端编程大门的机会。现在,我就来说说,游戏服务器端...
一,游戏服务器开发的工作介绍
近来遇到有很多人想从其它开发领域转到游戏服务器开发行业上来,他们或许觉得游戏服务器开发工资高,或许觉得做游戏服务器需要掌握的技术更高级,可以锻炼自己,或许觉得想换个环境等...
Carmelo是基于Java的游戏服务端框架,适合于页游和手游。它的主要特点是:
1. 利用Netty实现高效的NIO通信,同时支持TCP/HTTP协议
2. 完善的三层架构模型,易扩展
摘要: 本文作为游戏服务器端开发的基本大纲,是游戏实践开发中的总结。第一部分专业基础,用于指导招聘和实习考核, 第二部分游戏入门,讲述游戏服务器端开发的基本要点,第三部分服务端架构,介绍架构设计中的一...
他的最新文章
讲师:董岩
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)}

我要回帖

更多关于 计算机外储存器 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信