ESFramework FAQ -- ESFramework 常见问题解答
关于在使用通信框架ESFramework过程中遇到的常见问题,我们做了一个整理总结,并给出了解决问题的步骤或方案,大家可以按照指定的步骤发现和解决问题。
一. 常用网络检测命令
1. Ping -- 网络是否连通?延迟有多大?网络抖动情况如何?
如: ping 192.168.0.123 -t
2. telnet -- tcp 端口能连上?
如: telnet 192.168.0.123 4530
3. tracert -- 当到服务器的网络不顺畅时,可发现路由上是哪些节点“卡”?
如: tracert -d 192.168.0.123
4. 如何查看局域网中的电脑对外的公网IP地址?
在浏览器中打开网址 www.whereismyip.com , 页面将显示当前电脑的对外IP。
5. 如何让Windows 服务器允许 ping?
如果服务器禁止了ping,可按如下操作:控制面板->Windows防火墙->高级->ICMP->设置->将"允许传入回显请求"项勾上。
二. 常见异常信息解决
1. IRapidPassiveEngine 的 Initialize 方法抛出异常:Timeout waiting for reply ! 或者 Timeout to connect server!
(1)客户端和服务端的UserID的最大长度是否一致。可查找 GlobalUtil 的 SetMaxLengthOfUserID 静态方法。
(2)ping一下服务器,看到服务器的网络情况如何。
(3)如果使用的是ESFramework的试用版本,则检查SDK是否已经过期。
(4)如果服务端是加密狗授权的正式版本,有可能是加密狗松动或USB电源休眠而导致加密狗失效,可查看服务端运行目录下 ESF_AuthorizedError.txt 中的记录以确认。
2. ICustomizeOutter的Query方法抛出异常:There is an exception occured when {0} handing the query of {1}.
(1)该异常说明Query请求的处理方(可能是服务器或另一个在线客户端)在处理该请求时出现了异常,可以查看处理方的ESF日志来得到异常的详细信息。
(2)异常信息中的第一个占位符{0}的值,是处理方的UserID。如果是"_0",则表示是服务端。
(3)异常信息中的第二个占位符{1}的值,是自定义请求信息的类型,对应Query方法中的informationType参数。
3. ICustomizeOutter的Query方法抛出异常:Timeout waiting for reply !
(1)该异常含义是等待Query的处理回复超时。
(2)超时的常见原因有如下两个:Query请求的处理方处理该请求使用了太多的时间;或者,网络缓慢,而且回复的数据量太大,需要很长的传送时间。
(3)解决方案:
a. 优化请求处理的流程与算法,加快请求处理速度。
b. 将等待回复的最大超时设置得大一些。(对应IRapidPassiveEngine的WaitResponseTimeoutInSecs属性,默认值为30秒)。
c. 使请求的数据和回复的数据都尽可能地小。
d. 如果c无法做到,则建议不要使用同步调用机制Query,改用SendBlob方法,请求信息和/或回复信息使用SendBlob进行发送(内部使用分块发送机制)。
4. ICustomizeOutter的Query方法抛出异常:Network connection is disconnected !
(1)该异常含义是等待Query回复的过程中,与服务器的TCP连接断开了。
(2)TCP连接断开虽说大部分是网络原因,但是,要注意,在网络不是很顺畅时,一次性发送比较大块的数据,可能会导致TCP连接断开。
(3)为了防止(2)的情况出现,对于请求信息或回复信息的数据较大(比如超过4k)的情况,那么Query就不再适合,建议改用SendBlob方法(内部使用分块发送机制)。
(4)如果是IRapidPassiveEngine 的 Initialize方法抛出该异常,通常是客户端与服务端的UserID的最大长度设置得不一致导致的。(GlobalUtil的SetMaxLengthOfUserID方法)
5. 发送消息时抛出异常:Size of message to be post overflow!
在Rapid引擎初始化之前调用GlobalUtil的SetMaxLengthOfMessage方法设置消息的最大长度,客户端与服务端均须设置,且要设置成一致。
public static void SetMaxLengthOfMessage(int maxLen);
该方法详细说明请参见这里。
6. IRapidServerEngine 的 Initialize 方法抛出异常:无法加载或初始化请求的服务提供程序。
该错误通常是由于电脑上的Winsock协议配置有问题,可以用netsh winsock reset命令重置Winsock目录来解决。
解决方案:(1)单击“开始”,运行中输入 cmd。(2)输入命令:netsh winsock reset 。(3)根据提示,重启电脑。
7. 服务端启动时,出现错误提示框:“xxxxxxxx的类型初始值设定项引发异常”
抛出这个异常时,即使在Program.cs的Main方法加了catch也捕捉不到的,这种情况通常是全局静态实例构造时,抛出的异常。至于具体的原因是什么,需要点击弹出的提示框的下方的“查看详细信息...”,然后再一层层地找到最里面的那个InnerException,便可发现真正的原因是什么。
8. IRapidServerEngine 的 Initialize 方法抛出异常:以一种访问权限不允许的方式做了一个访问套接字的尝试。
该错误实际是因为 IRapidServerEngine 要监听的TCP端口被其它进程占用了。
解决方案:(1)找出占用该端口的进程:netstat -ano|findstr 4530。(2)关掉占用进程。(3)重新启动ESFramework服务端。
9. CompactPropertySerializer 的 Deserialize 方法抛出 SerializeException 异常。
该错误是因为反序列化失败报错了。
比如甲方将对象A通过 CompactPropertySerializer 序列化成byte[]后发送给乙方,乙方收到byte[]后将其反序列化成A对象时就报错了,这个错误的根本原因在于:甲方与乙方所使用的A的定义不一致,更具体地说,是双方所用的A class 的定义中的所有可读写(get,set)的属性不完全一致。
常见的情况是:修改了消息协议类的定义,甲乙双方中只有一端更新了,另一端还是使用的老的定义。
三. 疑问解答
1. IRapidPassiveEngine 与服务端的连接断开后,一直没有自动重连成功的原因有哪些?
(1)与服务器之间的网络是否已经恢复?
(2)IRapidPassiveEngine 的 AutoReconnect 属性是否为false?
(3)当前客户端是否是被挤掉线(即在其它地方登录了同一个帐号,会触发IBasicOutter的BeingPushedOut事件)?如果是被挤掉线的,则不会自动重连。
(4) 当前客户端是否是被踢掉线的(会触发IBasicOutter的BeingKickedOut事件)?如果是被踢掉线的,则不会自动重连。
(5) 是否在重连时,服务端验证其帐号密码失败了?(IRapidPassiveEngine 的 RelogonCompleted 事件的 LogonResponse 参数会反应出来)
2. 向对方发送自定义信息,对方没有进入ICustomizeHandler的HandleInformation方法?
(1)发送自定义信息时,传入的对方的UserID参数的值是否正确?必须要与对方的登录帐号完全一致(严格区分大小写的)。
(2)自定义信息处理器(ICustomizeHandler)的实例是否注入到了Rapid引擎?
(3)如果处理器是实现的 IIntegratedCustomizeHandler 接口,那么,查看其CanHandle方法的实现,看发送的信息的类型是否在其处理范围内?
3. 客户端引擎IRapidPassiveEngine 初始化时,serverIP这个参数能使用域名吗?
方案:先将域名转换成IP,然后再传给Initialize方法。System.Net 命名空间下有个Dns类,它的GetHostAddresses方法就可以将域名转换成 IP。
4. 好友/联系人 上下线事件没有触发?
(1)检查好友/联系人管理器是否注入到引擎,即 RapidServerEngine 的 ContactsManager 属性。
(2)是否开启通知
rapidServerEngine.ContactsController.ContactsConnectedNotifyEnabled= true;
rapidServerEngine.ContactsController.ContactsDisconnectedNotifyEnabled=
true;
(3)检查服务端IContactsManager的该方法的实现:public List<string> GetContacts(string userID)。
(4)在IContactsManager的GetContacts方法中加断点,看看返回的列表中是否包含了要通知的目标用户的ID。
5. 如何在服务端自动记录每个用户上下线的时间以及掉线的原因?
解答:服务端 IRapidServerEngine 有个 SecurityLogEnabled 属性,在SecurityLogEnabled初始化之前将其设置为true,便会自动记录用户上下线日志。
日志文件是位于运行目录下的 ESFrameworkLog.txt 或 ESF_SecurityLog.txt(新版本SDK) 。
四. 故障排查
4. ESFramework 服务端报OutOfMemoryException,要如何排查?
程序报OutOfMemoryExcepetion,表示操作系统分配给进程的内存已被用完(32位进程的最大使用内存大概是1.7G左右),当进程再次提出分配内存请求时,便会报 OutOfMemoryExcepetion。
(1)如果服务端是支持WebSocket客户端的,那么要注意最大消息尺寸的设置(GlobalUtil的SetMaxLengthOfMessage方法)。
比如,设置的最大消息尺寸为1M,那么,服务端将为每个在线的用户分配1M的缓冲区来接收消息。如果是此设置导致,可以尝试将其设置为10240。
(2)检查程序的业务逻辑,看看哪些地方分配了比较大块的内存?或者,是否存在内存泄漏(分配了内存一直没有释放)?
(3)如果排除了前面两点,程序确实需要用到很大的内存,那么可以考虑将程序编译为64位运行。
五. 综合
1. ESFramework 服务端如何暴露 Web API ?
通常的解决方案有两种:
(1)ESFramework 本身自带了 WebSocket 客户端引擎(ESFramework.WebSocket.js),可以使用该引擎与ESFramework服务端进行通信。
(2)如果觉得使用WebSocket 比较麻烦,则可以使用FastHttpApi框架在服务端暴露标准的HTTP接口。具体步骤如下所示:
添加BeetleX.dll、BeetleX.FastHttpApi.dll的引用。
注:需要在运行目录下添加System.Memory.dll、System.Runtime.CompilerServices.Unsafe.dll 这两个dll。
实现控制器:添加一个WebAction 类:
[Controller] [Options(AllowOrigin = "*")] public class WebAction { public object GetStarted(string email) { return new TextResult($"{email} {DateTime.Now}"); } }
在程序入口处,定义HttpApiServer,注册控制器,并打开服务。
private static BeetleX.FastHttpApi.HttpApiServer mHttpApiServer; mHttpApiServer = new BeetleX.FastHttpApi.HttpApiServer(); mHttpApiServer.Options.Port = 8011; mHttpApiServer.Register(typeof(WebAction).Assembly); mHttpApiServer.Open();
如此,一个标准的Get方式的Web接口已经准备好,可以在浏览器中输入如下网址测试:
http://127.0.0.1:8011/GetStarted?email=1234
3. 如何让 ESFramework 同时支持 WSS(带 SSL 加密的 WebSocket) ?
最新的ESFramework已经直接支持wss客户端了(如何使用?)。
-----------------------------------------------------------------------------------------------------------------------------------------------
Q Q:168757008