[fix]Config创建默认配置文件的开关Runtime.CreateConfigOnMissing,仅需对自动创建生效,而不应该阻止用户主动Save
智能大石头 编写于 2024-08-09 00:30:41 石头 提交于 2024-08-10 14:22:24
X
using System;
using System.Net;
using System.Net.Sockets;

namespace NewLife.Net.Modbus
{
    /// <summary>UDP传输</summary>
    public class UdpTransport : ITransport, IDisposable
    {
        #region 属性
        private String _HostName;
        /// <summary>主机名</summary>
        public String HostName { get { return _HostName; } set { _HostName = value; } }

        private Int32 _Port;
        /// <summary>端口</summary>
        public Int32 Port { get { return _Port; } set { _Port = value; } }

        private Int32 _Timeout = 3000;
        /// <summary>超时。默认3000ms</summary>
        public Int32 Timeout { get { return _Timeout; } set { _Timeout = value; } }

        private UdpClient _Client;
        /// <summary>客户端</summary>
        public UdpClient Client { get { return _Client; } set { _Client = value; } }

        private Int32 _ExpectedFrame;
        /// <summary>读取的期望帧长度,小于该长度为未满一帧,读取不做返回</summary>
        public Int32 FrameSize { get { return _ExpectedFrame; } set { _ExpectedFrame = value; } }
        #endregion

        #region 构造
        /// <summary>使用监听口初始化</summary>
        /// <param name="listenPort"></param>
        public UdpTransport(Int32 listenPort)
        {
            Port = listenPort;
        }

        /// <summary>初始化</summary>
        /// <param name="host"></param>
        /// <param name="port"></param>
        public UdpTransport(String host, Int32 port)
        {
            HostName = host;
            Port = port;
        }

        /// <summary>析构</summary>
        ~UdpTransport() { Dispose(false); }

        /// <summary>销毁</summary>
        public void Dispose() { Dispose(true); }

        /// <summary>销毁</summary>
        /// <param name="disposing"></param>
        protected virtual void Dispose(Boolean disposing)
        {
            if (disposing) GC.SuppressFinalize(this);

            Close();
        }
        #endregion

        #region 方法
        /// <summary>打开</summary>
        public void Open()
        {
            if (Client == null || !Client.Client.Connected)
            {
                Client = new UdpClient(HostName, Port);
                if (Timeout > 0) Client.Client.ReceiveTimeout = Timeout;
            }
        }

        /// <summary>关闭</summary>
        public void Close()
        {
            if (Client != null) Client.Close();
        }

        /// <summary>写入数据</summary>
        /// <param name="buffer">缓冲区</param>
        /// <param name="offset">偏移</param>
        /// <param name="count">数量</param>
        public void Send(Byte[] buffer, Int32 offset = 0, Int32 count = -1)
        {
            Open();

#if !MF
            WriteLog("Write:{0}", BitConverter.ToString(buffer));
#endif

            if (count < 0) count = buffer.Length - offset;

            var sp = Client;
            lock (sp)
            {
                if (offset == 0)
                    sp.Send(buffer, count);
                else
                    sp.Send(buffer.ReadBytes(offset, count), count);
            }
        }

        /// <summary>读取指定长度的数据,一般是一帧</summary>
        /// <param name="buffer">缓冲区</param>
        /// <param name="offset">偏移</param>
        /// <param name="count">数量</param>
        /// <returns></returns>
        public Int32 Receive(Byte[] buffer, Int32 offset = 0, Int32 count = -1)
        {
            Open();

            if (count < 0) count = buffer.Length - offset;

            var size = 0;
            var sp = Client;
            lock (sp)
            {
                try
                {
                    var remoteEP = new IPEndPoint(IPAddress.Any, 0);
                    var data = sp.Receive(ref remoteEP);
                    if (data != null && data.Length > 0)
                    {
                        size = data.Length;
                        // 计算还有多少可用空间
                        if (size > count) size = count;
                        buffer.Write(offset, data, 0, size);
                    }
                }
                catch { }
            }

#if !MF
            WriteLog("Read:{0}", BitConverter.ToString(buffer, offset, size));
#endif

            return size;
        }
        #endregion

        #region 异步接收
        /// <summary>开始监听</summary>
        public void ReceiveAsync()
        {
            if (Client == null)
            {
                Client = new UdpClient(Port);
                if (Timeout > 0) Client.Client.ReceiveTimeout = Timeout;
            }

            // 开始新的监听
            Client.BeginReceive(OnReceive, Client);
        }

        void OnReceive(IAsyncResult ar)
        {
            // 接收数据
            var server = ar.AsyncState as UdpClient;
            var ep = new IPEndPoint(IPAddress.Any, 0);
            var data = server.EndReceive(ar, ref ep);

            // 开始新的监听
            server.BeginReceive(OnReceive, server);

            // 分析处理
            if (Received != null)
            {
                data = Received(this, data);

                // 数据发回去
                if (data != null) server.Send(data, data.Length, ep);
            }
        }

        /// <summary>数据到达事件,事件里调用<see cref="Receive"/>读取数据</summary>
        public event TransportEventHandler Received;
        #endregion

        #region 日志
        /// <summary>输出日志</summary>
        /// <param name="formart"></param>
        /// <param name="args"></param>
        public static void WriteLog(String formart, params Object[] args)
        {
#if !MF
            NewLife.Log.XTrace.WriteLine(formart, args);
#endif
        }
        #endregion
    }
}