一个中间件,一个客户端,都是自己写的。客户端主动现寻求其较好的解决方案。或者,帮我解决我的这个构想。客户端与中间件之间通讯的包头有通讯系列号的信息,客户端发送一个请求,在客户端记录一个缓存,其Key是这个通讯系列号。
希望在中间件返回这个通讯系列号的数据包之后,客户端会有一个事件或者啥反映这个工作已经完成的动作,例如要从后台查询一个数据,发送请求之后,这个请求处在等待状态(但是不能影响通讯之间的程序运行),等数据包返回之后,这个程序继续;或者,客户端发送一个查询请求,然后客户端的程序仅仅在通讯管理程序上注册这个任务,不等待中间件返回的数据包了,等中间件返回数据包之后,通讯管理程序可以通知这个客户端模块这个工作已经完成了。
既然是用在通讯中的程序,所以必须有超时机制。现在是用阻塞方式,也就是使用了System.Threading.ManualResetEvent来等待数据返回。 遇到的困境是通过中间件来看,明明是有数据返回了,可是客户端还是判断其超时(超时时间是足够的)。比较困惑。

解决方案 »

  1.   

    那个东西貌似要单独安装的
    工具->扩展管理器   安装NuGet Package Manager 就哟了
      

  2.   

    代码很庞大,这里只是寻求一个解决方案,数据有返回指的是中间件跟踪有返回数据,因为通过WiFi,有可能信号极弱,因此不代表客户端真的有收到数据
      

  3.   

    用一些简单的代码来测试你的环境,这样有利于排除其他代码的干扰
    不要想着一下子everything ok.
    要一步步来
      

  4.   

    异步的机制基本上可以这样简单描述:你的客户端程序初始化一个GateWay实例对象,它负责与特定的某一个服务(在初始化GateWay时指定)进行通讯。比如说public void Send(long key, object message, Action<object> callback)回调中会把服务器端的返回带回来。于是客户端线程只要调用Send就结束了(或者说继续干别的去了)。然后当服务器端有返回,自然会在GateWay所创建的线程中来回调,你的客户端继续处理之后的方法。
    就GateWay来说:
    1. 它可以保存一个消息队列,例如其每一个单元都是public class Session
    {
        public long key;
        public Action<object> callback;
        public DateTime 超时时间;
    },这三个属性。然后可以每隔30秒钟轮询一次,对于超时的单元直接作为超时处理。
    2. 当收到服务器端异步发来的消息,解析出命令的基本内容之后,根据内容的key号从这个队列出取下相应的单元,调用其callback方法。实际上可以使用 ThreadPoll 来调用callback方法,这样性能更好。
      

  5.   

    你也可以扩展一下,例如public void Send(long key, object message, Action<object> succCallback, Action timeoutCallback)同样地在Session中也记录超时时的回调方法。这样当超时,通知客户端。而客户端根本就是异步的!
      

  6.   

    感觉CallBack是可以满足,可惜的是我了解不够,无法写出这样的代码来,能否帮得更详细点?谢谢
      

  7.   


      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;
                }
            }以上是接收的异步回调代码,发送类似
      

  8.   

        回调函数对我的这个架构来说有点麻烦,主要原因是由于WiFi有可能信号很差,也就是通讯性能很差,建立TCP连接的过程会较长,因此我是尽可能使用长连接,也就是建立的TCP在心跳包不超时的情况下不断开,如果心跳超时了才断开重新连接。因此使用了一个static的class作为TCP通讯的服务。
        由于程序有很多逻辑,因此会有很多class需要与中间件通讯,若是要使用回调函数的话,意味着在同一时间段需要传入多个class的回调函数,这种机制要如何解决,也就是该是谁的返回就调谁的回调函数。
      

  9.   


    嘿!你不是设计了key这个机制了么,同时谁send谁就注册了一个callback了么?显然,就算有100个线程在10秒钟内调用了10000次send,而返回也还是陆陆续续才得到的,而且就算是同一个客户对象先后调用两次send而返回是逆序(随便打乱次序)到来的,也丝毫没有问题啊?!
      

  10.   

    同一时间,session队列中有几百个请求都还没有得到服务器端的回应,这是很正常的事情。哪一个回应到来了,“根据内容的key号从这个队列出取下相应的单元”,也就是说根据key而“该市谁的返回就调用谁的回调函数”。
      

  11.   

    是否可以在那个static的通讯类中建立一个回调函数和其key的一个List<>,通讯中收到数据包,解开之后从这个List<>中查找到匹配的Key,然后调用这个Key对应的回调函数,完毕后销毁这个Key极其关联的回调函数?因为请求的class的每一次请求只希望被调用一次的回调函数,所以回调之后必须销毁
      

  12.   

    你的问题重复我的#9楼的描述了。不过不是什么“建立一个回调函数”。回调函数是人家发送数据是传给这个所谓的static通讯类的,然后它保存在队列中,不是它自己搞一个回调。另外.net无需什么销毁。你只要把相应的单元从队列中Remove,那么GC就会自动销毁它了。
      

  13.   

    随便写几行代码把,例如public static void SendMessage<SendType,ReceiveType>(SendType message, 
        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个请求的返回处理操作会异步触发,其执行顺序跟发送消息是的顺序毫无关系。
      

  14.   

    多谢,我先自己写个Demo测试下
      

  15.   

    显然对于SessionList的任何更改、遍历操作都应该是被lock的。因为会有很多线程同时来执行异步通讯,SessionList必须保证线程安全。
      

  16.   

    按照回调函数方式,是可以满足我的这个想法,客户端数据包一直发,每个包都打上一个系列号,系列号可以是一个顺序号,也可以是个GUID,然后等待服务端返回,服务端返回后,根据系列号调用指定的回调函数。不过我对这个不理解
    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
      

  17.   

    泛型参数。让你的输入的强类型的消息对象,以及回调时解析出来的强类型的结果对象,不用声明为object类型,而是强类型。当然如果你说都是string或者是byte[],那么你自己处理。泛型就意味着会更加好调用,因为不需要去处理什么string、byte[]转换,整个输入输出都是强类型的。。