C#异步SOCKET发送帮肋类,支持UDP,TCP

20 篇文章 0 订阅
7 篇文章 0 订阅

由于采用了池技术,需要指定最大池容量,以保证内存不泄漏.

另外C#中大量创造 SocketAsyncEventArgs会导致内存不能回收,


using System;
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Collections.Generic;
using System.Linq;



    /// <summary>
    /// 用于辅助异步发送Socket的帮肋类
    /// Ver1.2 增加了对 AsyncSendResult 的池管理,原因为发送数据时,占用了过大的内存.
    ///             增加了对不受控制的对像记数功能.
    /// </summary>
    public class AsyncSocketSendHelper
    {

        #region 客户端联接池
        /// <summary>
        /// 接收SAEA池集合
        /// </summary>
        private ConcurrentStack<SocketAsyncEventArgs> ReceiveSocketArgsPool = new ConcurrentStack<SocketAsyncEventArgs>();



        /// <summary>
        /// 初始化接收socketargs对象池
        /// </summary>
        protected void InitReceiveSocketArgsPool()
        {
   
        }

        /// <summary>
        /// 创建一个接收SAEA对象,设置最大接收字节数
        /// </summary>
        /// <returns></returns>
        protected virtual SocketAsyncEventArgs CreateReceiveSocketArgs()
        {
            SocketAsyncEventArgs e = new SocketAsyncEventArgs();
            e.Completed += IO_SendComleted;
            return e;
        }




        /// <summary>
        /// 租赁一个接收SAEA对象
        /// </summary>
        /// <returns></returns>
        protected virtual SocketAsyncEventArgs RentReveiveSocketArgs()
        {
            SocketAsyncEventArgs e;

            //增加已经发出的对像数据
            System.Threading.Interlocked.Increment(ref ss);
         

            return ReceiveSocketArgsPool.TryPop(out e) ? e : CreateReceiveSocketArgs();
        }


        private ushort _SocketArgsPoolNumber = 200;
        /// <summary>
        /// SocketAsyncEventArgs 池最大长度限制
        /// </summary>
        public ushort SocketArgsPoolNumber
        {
            get { return _SocketArgsPoolNumber; }
            set { _SocketArgsPoolNumber = value; }
        }
        //设置缓冲区
        private byte[] arr = new byte[1];

        private long ss;
        /// <summary>
        /// 已经创建但是还没有回收的对像个数,如果这个数据超过1000则表示可能有内存泄漏的风险.异步模式下出现
        /// </summary>
        public long OutControlSocketArgsNumber
        {
            get { return ss; }
        }


        /// <summary>
        /// 归还一个接收SAEA参数
        /// </summary>
        /// <param name="e">还池</param>
        protected virtual void GivebackReceiveSocketArgs(SocketAsyncEventArgs e)
        {
            if (e != null)
            {
                //减少已经发出的对像数据
                 System.Threading.Interlocked.Decrement(ref ss);
 
                e.UserToken = null;
                //最多只保存200个缓冲接收器功能
                if (ReceiveSocketArgsPool.Count > _SocketArgsPoolNumber)
                {
                    //移除事件
                    e.Completed -= IO_SendComleted;
                    e.SetBuffer(arr, 0, arr.Length);
                    e.Dispose();
                    return;
                }
                ReceiveSocketArgsPool.Push(e);
            }
        }

        #endregion

        /// <summary>
        ///UDP  发送数据服务
        /// </summary>
        /// <param name="socket">用于发送的Socket对像</param>
        /// <param name="udpTarget">udp远程终端点目标</param>
        /// <param name="buff">需要发送的数据</param>
        /// <param name="callBack">回调函数参数为:发送结果,目标节点,发送数据</param>
        /// <param name="userToken">用户数据 </param>
        public virtual void SendToAsyncByUDP(Socket socket, byte[] buff, EndPoint udpTarget = null, Action<AsyncSendResult> callBack = null, object userToken = null)
        {
            if (socket == null)
            {
                throw new NullReferenceException();
            }

            if (buff == null)
            {
                throw new NullReferenceException();
            }
            if (udpTarget == null)
            {
                throw new NullReferenceException();
            }
            SocketAsyncEventArgs e = RentReveiveSocketArgs();
            e.RemoteEndPoint = udpTarget;
            //设置发送缓冲区
            e.SetBuffer(buff, 0, buff.Length);
            try
            {
                //用户标识
                var token = new AsyncSendResult
                {
                    Result = false,
                    RemoteEndPoint = udpTarget.ToString(),
                    SendTime = DateTime.Now,
                    SendData = buff,
                    ResultTime = DateTime.Now,
                    CallBakc = callBack,
                    UserToKen = userToken,
                };
                e.UserToken = token;
                //发送数据
                if (!socket.SendToAsync(e))
                {
                    IO_SendComleted(socket, e);
                }
            }
            catch (SocketException)
            {
                //还池
                GivebackReceiveSocketArgs(e);
            }
            catch (ObjectDisposedException)
            {
                //还池
                GivebackReceiveSocketArgs(e);
            }

        }

        /// <summary>
        /// 发送数据服务
        /// </summary>
        /// <param name="socket">用于发送的Socket对像</param>
        /// <param name="buff">需要发送的数据</param>
        /// <param name="callBack">回调函数参数为:发送结果,目标节点,发送数据</param>
        /// <param name="userToken">用户数据 </param>
        /// <returns></returns>
        public virtual void SendToAsync(Socket socket, byte[] buff, Action<AsyncSendResult> callBack = null, object userToken = null)
        {
            if (socket == null)
            {
                throw new NullReferenceException();
            }

            if (buff == null)
            {
                throw new NullReferenceException();
            }

            SocketAsyncEventArgs e = RentReveiveSocketArgs();
            //设置发送缓冲区
            e.SetBuffer(buff, 0, buff.Length);
            try
            {
                //用户标识
                var token = new AsyncSendResult
                {
                    Result = false,
                    RemoteEndPoint = socket.RemoteEndPoint.ToString(),
                    SendTime = DateTime.Now,
                    SendData = buff,
                    ResultTime = DateTime.Now,
                    CallBakc = callBack,
                    UserToKen = userToken,
                };
                e.UserToken = token;
                //发送数据
                if (!socket.SendAsync(e))
                {
                    IO_SendComleted(socket, e);
                }
            }
            catch (SocketException)
            {
                //还池
                GivebackReceiveSocketArgs(e);
            }
            catch (ObjectDisposedException)
            {
                //还池
                GivebackReceiveSocketArgs(e);
            }
        }

        /// <summary>
        /// 发送数据后的完成功能
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected virtual void IO_SendComleted(object sender, SocketAsyncEventArgs e)
        {
            try
            {
                if (e.UserToken != null)
                {
                    AsyncSendResult token = e.UserToken as AsyncSendResult;
                    if (token != null)
                    {
                        //设置结果时间
                        token.ResultTime = DateTime.Now;

                        //发送数据OK
                        if (e.SocketError == SocketError.Success)
                        {
                            token.Result = true;
                            if (token.CallBakc != null)
                            {
                                token.CallBakc(token);
                            }

                        }
                        else
                        {
                            //发送数据失败
                            token.Result = false;
                            if (token.CallBakc != null)
                            {
                                token.CallBakc(token);
                            }
                        }
                    }
                }
            }
            finally
            {
                //还池
                GivebackReceiveSocketArgs(e);
            }
        }






    }

    /// <summary>
    /// 异步发送结果
    /// </summary>
    public class AsyncSendResult
    {
        /// <summary>
        /// 结果
        /// </summary>
        public bool Result { get; set; }

        /// <summary>
        /// 目标节点
        /// </summary>
        public string RemoteEndPoint { get; set; }

        /// <summary>
        /// 发送数据
        /// </summary>
        public byte[] SendData { get; set; }

        /// <summary>
        /// 发送时间
        /// </summary>
        public DateTime SendTime { get; set; }

        /// <summary>
        /// 结果返回时间
        /// </summary>
        public DateTime ResultTime { get; set; }


        /// <summary>
        /// 获取或设置与此操作关联的用户或应用程序对象。
        /// </summary>
        public object UserToKen { get; set; }

        /// <summary>
        /// 用于回调的委托
        /// </summary>
        internal Action<AsyncSendResult> CallBakc { get; set; }
    }



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
namespace ServerDemo { partial class ServerDemo { /// /// 必需的设计器变量。 /// private System.ComponentModel.IContainer components = null; /// /// 清理所有正在使用的资源。 /// /// 如果应释放托管资源,为 true;否则为 false。 protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Windows 窗体设计器生成的代码 /// /// 设计器支持所需的方法 - 不要 /// 使用代码编辑器修改此方法的内容。 /// private void InitializeComponent() { this.lb_ServerInfo = new System.Windows.Forms.ListBox(); this.bn_Resume = new System.Windows.Forms.Button(); this.bn_Stop = new System.Windows.Forms.Button(); this.bn_Start = new System.Windows.Forms.Button(); this.listBox1 = new System.Windows.Forms.ListBox(); this.cmbClient = new System.Windows.Forms.ComboBox(); this.btnSendto = new System.Windows.Forms.Button(); this.labClientCount = new System.Windows.Forms.Label(); this.SuspendLayout(); // // lb_ServerInfo // this.lb_ServerInfo.FormattingEnabled = true; this.lb_ServerInfo.ItemHeight = 12; this.lb_ServerInfo.Location = new System.Drawing.Point(14, 32); this.lb_ServerInfo.Name = "lb_ServerInfo"; this.lb_ServerInfo.Size = new System.Drawing.Size(572, 100); this.lb_ServerInfo.TabIndex = 61; // // bn_Resume // this.bn_Resume.Location = new System.Drawing.Point(174, 3); this.bn_Resume.Name = "bn_Resume"; this.bn_Resume.Size = new System.Drawing.Size(97, 23); this.bn_Resume.Ta

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值