FastSocket框架的回调实现

最近在GitHub上发现了FastSocket框架。初步用了一下发现实现很简单。几个Command类把需要执行的命令封闭起来,框架实现了协议,分包等功能。用户无需关心。用了一段时间发现少了两个比较主要的功能,心跳,回调。网上也没找到相关的文档。干脆自己实现。

一、首先是Server端。

第1步添加一个CallbackCommand

  public class CallbackCommand : ICommand<AsyncBinaryCommandInfo>
    {
        public void ExecuteCommand(IConnection connection, AsyncBinaryCommandInfo commandInfo)
        {
            if (commandInfo.Buffer == null || commandInfo.Buffer.Length == 0)
            {
                connection.BeginDisconnect();
                return;
            }
            commandInfo.Reply(connection, new byte[] { 0x00 });
            var v = MyService._connection.Find(model => model.ConnectionID == connection.ConnectionID);
            v.callBack = commandInfo;

        }
        public string Name { get { return "Callback"; } }
    }

第2步 客户端连入的时候将connection信息记录进一个Hash表。

        public override void OnConnected(IConnection connection)
        {
            base.OnConnected(connection);
            _connection.Add(connection);
        }


第3步 IConnection接口加入三个属性。

        /// <summary>
        /// 当前连接的最后心跳时间
        /// </summary>
        DateTime HeartTime { get; set; }
        /// <summary>
        /// 获取或设置与用户数据
        /// </summary>
        object UserData { get; set; }

        object callBack { get; set; }

最后心跳时间、客户端接入的用户信息、以及回调对象。


第4步 添加两个子线程,用于测试回调及定时心跳,这两个子,这两个子线程 可以在服务启动的时候直接启动。


        void TestSend() //主动推送消息到客户端
        {
            byte[] buffer = new byte[] { 0x00, 0x99, 0xAA, 0xFF };
            Packet packet = PacketBuilder.ToAsyncBinary("TestSend", 0, buffer);

            while (true)
            {
                foreach (var v in _connection)
                {
                    try
                    {
                        ((AsyncBinaryCommandInfo)v.callBack).Reply(v, buffer);
                    }
                    catch (Exception ex) { }
                }

                System.Threading.Thread.Sleep(1000);
            }
        }
        /// <summary>
        /// 心跳线程
        /// </summary>
        void SocketHeart()
        {
            while (!Globals.IsStop)
            {
                lock (_connection)
                {
                    for (int i = _connection.Count - 1; i >= 0; i--)
                        if (_connection[i].HeartTime < DateTime.Now.AddSeconds(0 - (30 * 3)))//超过三个心跳包,干掉
                        {
                            MyService.WriteLog("Action:\"RemoveConnection\"", _connection[i]);
                            _connection.RemoveAt(i);
                        }
                }
                System.Threading.Thread.Sleep(1000 * 10);
            }
        }

Server端到这里就可以了。接下来的客户端。


客户端这里需要解释一下。客户端在发送一个指令到服务器端的同时,会启动一个监听,因为每一个指令都有一个唯一的SeqlID,客户端在发送后启动一个监听,收到来自Server端的回复,并检查SeqID相同以后会清除这个监听。因为回调不允许清除监听,否则将不能接收到消息。那我就从这个角度考虑,把问题解决掉。


问题的关键在于BaseSocketClient类的OnMessageReceied方法,其中有一个 this._requestCollection.Remove(response.SeqID); 其中 _requestCollection就是回调队列,Remove方法就是找到这个回调并加以删除。


protected override void OnMessageReceived(IConnection connection, MessageReceivedEventArgs e)
        {
            base.OnMessageReceived(connection, e);

            int readlength;
            TResponse response = null;
            try
            {
                response = this._protocol.FindResponse(connection, e.Buffer, out readlength);
            }
            catch (Exception ex)
            {
                this.OnError(connection, ex);
                connection.BeginDisconnect(ex);
                e.SetReadlength(e.Buffer.Count);
                return;
            }

            if (response != null)
            {
                this.OnResponse(connection, response)

                <span style="background-color: rgb(255, 255, 51);">var request = this._requestCollection.Remove(response.SeqID);</span>

                if (request == null)
                    ThreadPool.QueueUserWorkItem(_ =>
                    {
                        try { this.HandleUnknowResponse(connection, response); }
                        catch (Exception ex) { SocketBase.Log.Trace.Error(ex.Message, ex); }
                    });
                else
                    ThreadPool.QueueUserWorkItem(_ =>
                    {
                        try { request.SetResult(response); }
                        catch (Exception ex) { SocketBase.Log.Trace.Error(ex.Message, ex); }
                    });
            }
            e.SetReadlength(readlength);
        }


接下来找到Remove方法,将Remove加以修改。因为客户端启动的第一件事情就是执行回调操作,所以SeqID == 1 ,我们就把这个SeqID一直保留,同样找到对_dic执行Remove操作的地方加以修改。


   public Request<TResponse> Remove(int seqID)
            {
                Request<TResponse> removed;
                if (seqID == 1 && this._dic.ContainsKey(seqID)) return this._dic[seqID];

                this._dic.TryRemove(seqID, out removed);
                return removed;
            }


倒数第二步。AsyncBinarySocketClient类里面添加回调操作。这里我做了一个回调事件。

        public delegate void OnCallback(byte[] buffer);
        public event OnCallback Callback = null;


并在Send方法里面添加该事件的实现。


 public Task<TResult> Send<TResult>(byte[] consistentKey, string cmdName, byte[] payload, Func<AsyncBinaryResponse, TResult> funcResultFactory, object asyncState = null)
        {
            if (string.IsNullOrEmpty(cmdName)) throw new ArgumentNullException("cmdName");
            if (funcResultFactory == null) throw new ArgumentNullException("funcResultFactory");

            var seqID = base.NextRequestSeqID();
            var cmdLength = cmdName.Length;
            var messageLength = (payload == null ? 0 : payload.Length) + cmdLength + 6;
            var sendBuffer = new byte[messageLength + 4];

            //write message length
            Buffer.BlockCopy(NetworkBitConverter.GetBytes(messageLength), 0, sendBuffer, 0, 4);
            //write seqID.
            Buffer.BlockCopy(NetworkBitConverter.GetBytes(seqID), 0, sendBuffer, 4, 4);
            //write response flag length.
            Buffer.BlockCopy(NetworkBitConverter.GetBytes((short)cmdLength), 0, sendBuffer, 8, 2);
            //write response flag
            Buffer.BlockCopy(Encoding.ASCII.GetBytes(cmdName), 0, sendBuffer, 10, cmdLength);
            //write body buffer
            if (payload != null && payload.Length > 0)
                Buffer.BlockCopy(payload, 0, sendBuffer, 10 + cmdLength, payload.Length);

            var source = new TaskCompletionSource<TResult>(asyncState);
            base.Send(new Request<Response.AsyncBinaryResponse>(consistentKey, seqID, cmdName, sendBuffer, ex => source.TrySetException(ex),
                response =>
                {
                    TResult result;
                    try { result = funcResultFactory(response); }
                    catch (Exception ex) { source.TrySetException(ex); return; }

                    source.TrySetResult(result);  
<span style="background-color: rgb(255, 255, 0);">                    if(cmdName == "Callback" && Callback != null)
                    {
                        Callback(result as byte[]);
                    }
</span>                }));
            return source.Task;
        }

最后一步,客户端实现这个回调事件,并发送回调操作到服务器。


            Globals.client.RegisterServerNode("127.0.0.1:8401", new System.Net.IPEndPoint(System.Net.IPAddress.Parse("127.0.0.1"), 8401));
            Globals.client.Callback += client_Callback;
            Globals.client.Send("Callback", new byte[] { 0x00 }, res => res.Buffer);


到这里基本就完成了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
感谢大家对北风之神SOCKET框架的支持。鼓励。下面是北风之神 3.1的更新内容: 修正BUG: 1.ZYSocketSuper 读取 配置文件的最大连接数 读错问题。 2.ZYSocketSuper 无法断开客户端的问题。 3.BuffList 数据包解析丢失问题。 4.例1,例2.客户端断开忘记释放调用SOCKET.CLOSE()的问题 新增功能 1.添加了一个ReadBytes 构造函数,此函数实现了在数据包在读取前需要回调的方法传入。(可以用来解密,解压缩 等功能) 2.添加了一个BufferFormat 类的构造,此函数实现了在数据包在生成前需要回调的方法传入。(可以用来加密,压缩 等功能) 3.添加了BufferFormat.FormatFCA(object o,FDataExtraHandle dataExtra)静态方法。可以用来在类格式化成数据包的时候进行加密压缩等功能 4.添加了ZYSocket.Security 命名空间,里面有传统的AES,DES算法的加解密类 5.添加了ZYSocket.Compression命名空间,里面有通过Deflate算法压缩类 6.开发了ReadBytes.Data属性,为ReadBytes里面的BYTE[]对象。值得注意的是 ReadBytes.Length为数据包原始长度,如果要得到解压缩后的数据包长度,请访问ReadByte.Data.length 新增代码 加解密实例测试 项目:演示了 AES DES 以及Deflate 的使用方法。 例3 - 例2的加密版 项目:就是讲例2通过DES 加密进行通讯的例子 连接测试工具 项目:很多朋友问我要连接数量测试工具。我一起的真的丢了。找不到了。所以重新写了一个 例4 项目:好多人让我写一个发送文件的例子,现在能如愿以偿了 by [email protected] BLOG:http://blog.csdn.net/luyikk QQ:547386448

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值