FAQ - ScutGame/Scut GitHub Wiki

此章节整理开发中碰到问题总结的FAQ

在使用Scut中有碰到的问题尽量提交到论坛中,更方便我们整理。

##Scut开发问题

  • Scut同时在线人数能达到多少?

同时在线人数跟CPU,内存,带宽都有关系的,具体性能见负载测试报告

服务器配置计量方法:

  • CPU:依据业务的运算量,较大可配置高些,8核基本应该够用;
  • 内存:以1个用户占1M计算;
  • 带宽:以1个用户按60K计算,这个是每秒并发人数,不是在线人数;
  • 启动时提示"NIC is not connected or no network"出错?

说明本机机器的网络有问题

  • 检查127.0.0.1是否能Ping通,并且关掉防火墙试试;
  • 检测网卡是否是正确版本,不正确需要升级;
  • 检查是否有多个网卡或外接wifi,禁用再试试。
  • 启动时提示"Redis Server is using Ip game server, it's path..."或"Server failed to start error:The game server is using Redis at host nam e "oneHostName" path D:\xxx\xxx."

说明Redis服务被其它的程序使用了,进入命令行窗口,使用redis-cli客户端删除"__RedisInfo"的键; 脚本如下:

> redis-cli -h 127.0.0.1 -p 6379
# 切换使用的Redis.DB
> select 0;
> del __RedisInfo;
select 0的0根据你的游戏redis数据库序号填写

一般的服务器是 一个Server对应一个Redis部署, 再扩新服时,会需要copy配置文件,由于人为原因可以会漏改配置文件,造成新服与旧服共用了一个存储区域,数据混乱掉;因此增加限制;如果不是这种一个Server对应一个Redis的架构, 可以增加配置键:

<add key="Slave.MessageQueue" value="Slave" />

6.7.9.10版本调整为使用机器名+路径绑定

  • Csscript目录下的脚本文件在VS中没有智能提示?

检查脚本文件的属性,是否是编译的方式;另外注意在Game项目中的Script目录下的文件不能设置编译的方式,因为它是以动态运行的,不能把这些脚本编译在exe中,会与动态编译的冲突。

  • 如何在项目中调试SCUT FRAMEWORK?

首先.net调试是需要*.pdb文件的,打开Scut 的Framework解决方案,编译Source, 接着双击“发布处理.bat”批处理文件将dll发布到上一级的Release目录下(需要xcopy命令支持); 接着将Release/Lib目录下的dll复制到项目中即可;要调试Source的某个文件, 只需要将文件拖到项目中并设置断点,再按F5运行当前项目;断点有生成显示的是实心的红色圆点, 如果是穿心圆点说明文件与dll里的版本不一致,需要重新按以上步骤替换dll。

  • 打开SCUT项目编译USING错误?

Scut要求是在.Net Framework 4.5.1以上版本运行的,检查是否有安装VS2013或.Net Framework 4.5.1运行时环境;在项目属性的生成选项以“.Net Framework 4.5.1”编译。

  • 代码中如何查USING的命名空间?

在VS中将鼠标移到需要增加using命名空间的类上,会在旁边显示一个小图标,下拉选中using的命名空间,VS会自动帮助你加到文件using部分;或者安装一个代码生成工具VS插件ReSharper(QQ群文件有提供),提高编码效率。

  • 是否有实现同一个帐号再次登录挤掉的功能?

使用AuthorizeAction类判断GameSession对象的OldSessionId属性来识别。

  • 渠道登录中间件配置的ID如何设置?

配置的ID是通过客户端上传的RetailID参数来区分的,可以自己分配, 与客户端对应上就可以。

  • 实体属性修改后没有保存到Redis和DB中?

Model是否是独立另一个项目,需要使用IL打开Model.dll检查Entity的Set属性代码是否有调用BindAndNotify或BindAndChangeProperty方法,没有需要在项目.csproj配置注入脚本;Model是以脚本方式,需要检查Entity的SchemaTable配置,只读或只写属性不会触发Changed事件。

  • 游戏服的缓存数据是如何更新的?

每个实体的属性都绑定有Changed事件,当属性发现设置值,新增和删除实体时时会触发事件,所有Change事件会提交到Redis的消息队列中(Key以“__”开头); 由另一线程监控这个消息队列(每100毫秒),当有新消息时会将数据更新到Redis的Model存储区中(key以“$”开头),更新失败将存储到Redis的Error消息队列;根据config配置中的“EnableWriteToDb”键和实体SchemaTable属性的“IsStoreInDb”值判断是否要更新到数据库,为了降低数据库的IO高,需要更新数据库的实体先放到等待消息队列中,间隔(每五分钟)一段时间将实体转换成sql语句放入Sql执行消息队列中,Sql执行消息队列启动线程(配置10个线程)每100毫秒执行写入到数据库,如果执行出错将Sql语句存储到Redis的Sql Error消息队列。

  • 为什么数据库表里的数据修改了在游戏服缓存中没有?

原因是游戏服从数据库或Redis取出数据后会缓存在游戏服中,不会每次从数据库或Redis中取了,当游戏服的数据改变时会更新到数据库或Redis,在数据库或Redis修改数据是会被覆盖;当游戏服关掉重启时才会再次从数据库或Redis取数据;另外配置实体是只读类型的才会从数据库取数据,其它的只从Redis取数据,原因Scut是以Redis作为主要存储。

  • REDIS客户端查看存储的数据是否能显示JSON的格式?

可以在项目的Config配置中增加键“Cache.Serializer”值为“Json”,使用Json序列化的方式存储,设置前需要将Redis的数据清除,不能混合使用;建议在开发阶段使用Json,发布时使用“Protobuf”序列化的存储,减少Redis内存使用量。

  • 日志表增长比较大如何处理?

日志表比较大时,可以对表以日期水平方式分割,减小单张表的存储容量;在Model中定义一个Log类型的实体模型,并设置表名以“年月”或“年月日”的规则生成表,;设置EntityTable的“TableNameFormat”属性为“Log$date[yyyyMM]_{0}”(ex: Log201408_TableName)。

  • Model实体设计如何返回GetIdentity方法的值?

GetIdentity是对实体数据分类的ID,如:背包数据它的主键是ItemID(自增的),UserId(归属玩家),那么可以用UserId分类,GetIdentity返回UserId属性值,而不能用主键ItemID,如果一定要用ItemID,那么可以使用Share类型的结构(ShareEntity); 使用new PersonalCacheStruct().FindKey(参数1),参数1就是GetIdentity()的值。

  • 使用GameHttpHost时提示Httplistener监听启动拒绝问题?

检查GameServer.exe启动是否使用管理员帐号运行

  • 玩家离线怎么通知应用层和断线重连怎么处理?

当Socket断线时会调用MainClass类中有OnDisconnected方法,这此处理业务层逻辑;断线重连根据sid参数自动恢复连接,不需要自己处理。

  • 如何在游戏服内调用WebService服务?

首先右击项目的“引用”,选择“添加服务引用”,在弹出的窗口地址输入WebService服务地址后,点“确定”;VS会自动生成的调用WebService服务的调用代码和配置文件,需要将Reference.cs文件Copy到Script/CsScript/References目录下;另外找到“app.config”配置文件,将“system.serviceModel”结点的配置复制到“GameServer.exe.config”中。

  • 在线用户如何获取?

所有的会话都是由GameSession管理的,GameSession.GetOnlineAll方法可以获取在线玩家。

  • 传输过程有没有对数据加密?

没有对数据加密,有对请求数据做签名较验,可以在Config配置“Product.SignKey”,注意需要跟客户端的签名Key一致。

  • 不需要身份较验访问ACTION如何处理?

在Action类中重写IgnoreActionId属性,并返回false。

  • 请求的身份认证如何处理?

客户端请求时服务器会分配一个GameSession对象,登陆时较验用户帐号与密码,成功后调用GameSession对象Bind方法绑定身份。

  • SCUT的二进制协议流粘包如何处理?

在包的前面增加一个int的长度表示包的字节大小,拆包时先读取4位字节转换成int类型的长度(L),接着判断剩余包的长度大于等于L时,说明包已经全部接收完,读取L长度的字节;如果长度小于L时,则继续等待。

  • 通讯协议的头部ST字段的作用是什么?

头部St字段是一个时间缀(预留字段),表示这次的请求有效期多久,防止请求被拦截后发起恶意的请求,增加安全性,目前只使用签名较验,这个字段暂时未启用。

  • 通讯协议的头部SID和UID如何获取值?

Sid表示请求的会话ID,在客户连接成功后由服务器自己产生;Uid是用户登录成功后的身份标识,由帐号中心分配唯一的编号,在未登录前的请求客户端给sid的值空串,Uid的值0;登录成功后服务器下发sid和Uid,客户接收到需要存储起来,下一请求时上传sid和uid的值。

  • ACTION协议的方法执行顺序?

调用顺序是GetUrlElement (获取请求参数处理)->TakeAction(处理逻辑)->BuildPacket(封包下发)。

  • Scut Socket的IO是阻塞还是非阻塞模型?

接收数据是异步阻塞模型,IO使用的缓冲区是复用的。

  • SCUT支持HTTP短连接吗?

使用Consele控制台开启Http监听,在config配置中设置"Game.Http.Host"为"127.0.0.1",在IE中访问[http://127.0.0.1:8080/Service.aspx] ,(注: 6.7.9.0以上版本去掉对IIS部署的支持)

  • SCUT支持WebSocket连接吗?

支持,在6.7.9.5以上版本对WebSocket提供支持。

  • 如何配置Game.Script.DecodeFunc.Typename脚本加密发布?

Scut有提供一个加密脚本类库(ScutSecurity),它的密钥写在代码里,可以自己根据需要更换,使用时需要在Config中配置值为"ScutSecurity.ScriptDes,ScutSecurity",并从Release\Lib目录复制ScutSecurity.dll到项目中;在开发阶段可以注释掉这个配置,在发布时自己写工具批量加密脚本文件,并启用此配置。

  • 提示找不到相应的Action,报10000错误码怎么处理?

检查Script目录下是否有这个Action文件,检查Action文件的命名空间与GameServer.exe.config配置文件中"Game.Action.Script.TypeName"的是否一致

##Scut Sample问题

  • 客户端登陆没有反应或连接不上问题?

客户端在代码中设置的服务器地址是以域名(ddz.scutgame.com)的方式访问的,需要在本机Host文件中设置ddz.scutgame.com的域名转向,使用命令“telnet ddz.scutgame.com 9001”检测,或者客户端的请求连接地址改为本机IP(NetHelper.lua文件里配置);如果连接是成功的,检查服务器的Log\Exception目录是否有异常日志,有提示“SQL server error 40”错误的是服务器的连接字符串配置有问题。

##协议工具问题

协议工具需要部署在IIS7.0以上版本上,需要安装.NET 4.0以上版本;生成代码功能并不是生成可执行的代码,有些上方需要手动修改。

  • 协议工具部署完成后,打开页面显示iframe错误?

检查Web.config的配置;检查C:\windows\Temp目录给everyone用户加上读写目录的权限;IIS网站根目录“功能视图”的“ISAPI和CGI限制”中“ASP.NET V4.0”是否配置有允许。

  • 页面按钮点击没有反应?

检查Log目录下的是否有异常,如果是数据库出错检查下连接字串符串的配置是否正确;使用Mysql数据库时要注意下server配置使用“.”号的问题,换成“localhost”试试。

  • 协议工具有没有说明文档?

如何使用协议工具平台

##客户端SDK使用问题

  • 服务器推送Unity3d的消息怎么接收?

Unity请求的与推送的消息都是由线程监听,通过SocketConnect类的CheckReceive方法检测是否有消息,如果是推送的消息MsgId为0,转向到注册的OnPushCallback回调方法处理,Net类中处理回调会将消息分发到指定的Action协议处理。