一个中间件,一个客户端,都是自己写的。客户端主动现寻求其较好的解决方案。或者,帮我解决我的这个构想。客户端与中间件之间通讯的包头有通讯系列号的信息,客户端发送一个请求,在客户端记录一个缓存,其Key是这个通讯系列号。
希望在中间件返回这个通讯系列号的数据包之后,客户端会有一个事件或者啥反映这个工作已经完成的动作,例如要从后台查询一个数据,发送请求之后,这个请求处在等待状态(但是不能影响通讯之间的程序运行),等数据包返回之后,这个程序继续;或者,客户端发送一个查询请求,然后客户端的程序仅仅在通讯管理程序上注册这个任务,不等待中间件返回的数据包了,等中间件返回数据包之后,通讯管理程序可以通知这个客户端模块这个工作已经完成了。
既然是用在通讯中的程序,所以必须有超时机制。现在是用阻塞方式,也就是使用了System.Threading.ManualResetEvent来等待数据返回。 遇到的困境是通过中间件来看,明明是有数据返回了,可是客户端还是判断其超时(超时时间是足够的)。比较困惑。
希望在中间件返回这个通讯系列号的数据包之后,客户端会有一个事件或者啥反映这个工作已经完成的动作,例如要从后台查询一个数据,发送请求之后,这个请求处在等待状态(但是不能影响通讯之间的程序运行),等数据包返回之后,这个程序继续;或者,客户端发送一个查询请求,然后客户端的程序仅仅在通讯管理程序上注册这个任务,不等待中间件返回的数据包了,等中间件返回数据包之后,通讯管理程序可以通知这个客户端模块这个工作已经完成了。
既然是用在通讯中的程序,所以必须有超时机制。现在是用阻塞方式,也就是使用了System.Threading.ManualResetEvent来等待数据返回。 遇到的困境是通过中间件来看,明明是有数据返回了,可是客户端还是判断其超时(超时时间是足够的)。比较困惑。
工具->扩展管理器 安装NuGet Package Manager 就哟了
不要想着一下子everything ok.
要一步步来
就GateWay来说:
1. 它可以保存一个消息队列,例如其每一个单元都是public class Session
{
public long key;
public Action<object> callback;
public DateTime 超时时间;
},这三个属性。然后可以每隔30秒钟轮询一次,对于超时的单元直接作为超时处理。
2. 当收到服务器端异步发来的消息,解析出命令的基本内容之后,根据内容的key号从这个队列出取下相应的单元,调用其callback方法。实际上可以使用 ThreadPoll 来调用callback方法,这样性能更好。
void RecCallback(IAsyncResult ias) {
NetworkStream stream = ias.AsyncState as NetworkStream;
try {
stream.EndRead(ias);
int length = BitConverter.ToInt32(_buffer, 0);
byte[] buffer = new byte[length];
int rec = 0;
REC:
rec += stream.Read(buffer, rec, length - rec);
if (rec < length) {
goto REC;
} stream.BeginRead(_buffer, 0, 4, _recCallback, stream);
} catch (Exception ee) {
Log.Ins.Write(LogGrade.OFTEN, "接收数据时出现异常:{0}", ee);
_client.Client.Close();
_client = null;
}
}以上是接收的异步回调代码,发送类似
由于程序有很多逻辑,因此会有很多class需要与中间件通讯,若是要使用回调函数的话,意味着在同一时间段需要传入多个class的回调函数,这种机制要如何解决,也就是该是谁的返回就调谁的回调函数。
嘿!你不是设计了key这个机制了么,同时谁send谁就注册了一个callback了么?显然,就算有100个线程在10秒钟内调用了10000次send,而返回也还是陆陆续续才得到的,而且就算是同一个客户对象先后调用两次send而返回是逆序(随便打乱次序)到来的,也丝毫没有问题啊?!
Action<ReceiveType> succCallback, Action<Exception> exceptionCallback, Action timeoutCallback)
{
byte[] data= 序列化命令对象(message);
lock(SessionList)
{
Key++; //在Lock中,因此可以保证Key唯一
var session= new Session{ key= Key,
succCallback=succCallback,
timeOutCallback=timeoutCallback,
exceptionCallback=exceptionCallback,
超时时间=DateTime.Now.AddSeconds(60);
};
SessionList.Add(session);
}
调用底层通讯方法的send方法(data);
}异步发送消息就是这样,这基本就完成了。一个唯一的Key保证在多线程调用这个static Send方法时也是唯一的。然后每一个客户调用时的回调注册到你的“static通讯类”中了,实际上就是保存到SessionList队列中了。当服务器端返回消息,根据发来的Key就可以从sessionList上摘下Session对象,并调用其回调,所以“该是谁的返回就调谁的回调函数”。而当30秒轮询时对于那些已经超时的Session也是一样摘下来,然后调用其另外一个回调。对于服务器端返回的了消息,但是是报告处理异常的,也是一样,调用客户端注册的另外一个回调。跟使用这个static Send方法有多少线程、多少程序没有关系,并且服务器端可以以任意次序返回消息处理。例如一个客户程序可以连续发送10个请求,然后就去干别的事情了。反正这10个请求的返回处理操作会异步触发,其执行顺序跟发送消息是的顺序毫无关系。
public static void SendMessage<SendType,ReceiveType>(SendType message,
Action<ReceiveType> succCallback, Action<Exception> exceptionCallback, Action timeoutCallback)SendType,ReceiveType 是什么?var session= new Session{...
succCallback=succCallback, 这里的succCallback该如何申明
timeOutCallback=timeoutCallback, 这里的timeOutCallback该如何申明
exceptionCallback=exceptionCallback, 这里的exceptionCallback该如何申明还有,var好像无法申明List<>对不,是否要建立一个Session的class
我有一个关于通讯性能方面的帖,如果这方面有见解的话,麻烦帮我看看
http://topic.csdn.net/u/20120219/20/6df9f815-10a6-47c5-8038-4d5f32036536.html