v7.3.2018.0614   重构高性能资源池,减少GC压力,增加线程池,让异步任务得到平等竞争CPU的机会
大石头 编写于 2018-06-14 17:56:44
X
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using NewLife.Net.Sockets;

namespace NewLife.Net.Udp
{
    /// <summary>增强的UDP客户端</summary>
    public class UdpClientX : SocketClient, IUdp
    {
        #region 属性
        /// <summary>已重载。</summary>
        public override ProtocolType ProtocolType { get { return ProtocolType.Udp; } }
        #endregion

        #region 接收
        /// <summary>异步接收</summary>
        public override void ReceiveAsync()
        {
            StartAsync(e =>
            {
                var client = Client;
                if (client == null || Disposed) { e.Cancel = true; return false; }

                // 兼容IPV6
                var address = AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any;
                e.RemoteEndPoint = new IPEndPoint(address, 0);
                // 不能用ReceiveAsync,否则得不到远程地址
                return client.ReceiveFromAsync(e);
            });
        }
        #endregion

        #region 发送
        /// <summary>发送数据</summary>
        /// <param name="buffer">缓冲区</param>
        /// <param name="offset">位移</param>
        /// <param name="size">写入字节数</param>
        /// <param name="remoteEP">远程终结点</param>
        public virtual void Send(Byte[] buffer, Int32 offset = 0, Int32 size = 0, EndPoint remoteEP = null)
        {
            var socket = Client;
            if (!socket.IsBound) Bind();

            if (size <= 0) size = buffer.Length - offset;
            if (remoteEP != null && Socket == null) AddressFamily = remoteEP.AddressFamily;
            //if (remoteEP != null && ProtocolType == ProtocolType.Udp)
            if (socket.Connected)
                socket.Send(buffer, offset, size, SocketFlags.None);
            else
                socket.SendTo(buffer, offset, size, SocketFlags.None, remoteEP);

            //return this;
        }

        /// <summary>广播数据包</summary>
        /// <param name="buffer">缓冲区</param>
        /// <param name="offset">偏移</param>
        /// <param name="size"></param>
        /// <param name="port"></param>
        public void Broadcast(Byte[] buffer, Int32 offset, Int32 size, Int32 port)
        {
            if (!Client.EnableBroadcast) Client.EnableBroadcast = true;

            if (size <= 0) size = buffer.Length - offset;
            Client.SendTo(buffer, offset, size, SocketFlags.None, new IPEndPoint(IPAddress.Broadcast, port));
        }

        /// <summary>广播字符串</summary>
        /// <param name="message"></param>
        /// <param name="port"></param>
        public void Broadcast(String message, Int32 port)
        {
            var buffer = Encoding.UTF8.GetBytes(message);
            Broadcast(buffer, 0, buffer.Length, port);
        }
        #endregion

        #region 创建会话
        private ISocketSession _session;

        /// <summary>为指定地址创建会话。对于无连接Socket,必须指定远程地址;对于有连接Socket,指定的远程地址将不起任何作用</summary>
        /// <param name="remoteEP"></param>
        /// <returns></returns>
        public override ISocketSession CreateSession(IPEndPoint remoteEP = null)
        {
            var socket = Client;
            if (!socket.Connected)
            {
                if (remoteEP == null) throw new ArgumentNullException("remoteEP", "未连接Udp必须指定远程地址!");

                return new UdpSession(this, remoteEP);
            }
            else
            {
                // 已连接。返回已有的
                if (_session == null) _session = new UdpSession(this, remoteEP);
                return _session;
            }
        }
        #endregion
    }
}