UdpServer

Udp服务端:

cs 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
using System.IO;
using Notify.Log;

namespace UdpSer
{
    public class UdpServer
    {
        // 创建UDP端点,并绑定到本地端口
        IPEndPoint localEndPoint;
        // 创建UDP套接字
        private UdpClient udpServer = new UdpClient();
        private volatile bool runing = false;
        private byte[] receiveBytes = new byte[2048];
        private byte[] sendBytes = new byte[2048];
        private Queue<LogContentV2> logBuffer = new Queue<LogContentV2>();
        private Thread listenThread;
        public int LogBufferCount { get { return this.logBuffer.Count; } }
        public LogContentV2 Log { get { return this.logBuffer.Dequeue(); } }
        public UdpServer()
        {
            // 创建UDP端点,并绑定到本地端口
            localEndPoint = new IPEndPoint(IPAddress.Any, 8421);
            // 创建UDP套接字
            udpServer = new UdpClient(localEndPoint);
            if (this.listenThread == null || this.listenThread.IsAlive == false)
            {
                this.listenThread = new Thread(new ThreadStart(TaskRunning));
                this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
            }
            logBuffer.Enqueue(new LogContentV2(LogLevelV2.Infor, "UdpServer default constructed."));
        }
        public UdpServer(int port = 8421)
        {
            // 创建UDP端点,并绑定到本地端口
            localEndPoint = new IPEndPoint(IPAddress.Any, port);
            // 创建UDP套接字
            udpServer = new UdpClient(localEndPoint);
            if (this.listenThread == null || this.listenThread.IsAlive == false)
            {
                this.listenThread = new Thread(new ThreadStart(TaskRunning));
                this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
            }

            logBuffer.Enqueue(new LogContentV2(LogLevelV2.Infor, "UdpServer constructed."));
        }
        public void Startup()
        {
            this.localEndPoint = new IPEndPoint(IPAddress.Any, 8421);
            if (this.listenThread == null || this.listenThread.IsAlive == false)
            {
                this.listenThread = new Thread(new ThreadStart(TaskRunning));
                this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
            }
            switch (listenThread.ThreadState)
            {
                case System.Threading.ThreadState.Unstarted:
                    this.listenThread.Start();
                    runing = true;
                    break;
                case System.Threading.ThreadState.StopRequested:
                case System.Threading.ThreadState.AbortRequested:
                case System.Threading.ThreadState.Aborted:
                case System.Threading.ThreadState.Stopped:
                case System.Threading.ThreadState.Suspended:
                case System.Threading.ThreadState.SuspendRequested:
                    this.listenThread.Abort();
                    this.listenThread = new Thread(new ThreadStart(TaskRunning));
                    this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
                    this.listenThread.Start();
                    runing = true;
                    break;
                case System.Threading.ThreadState.Running:
                    runing = true;
                    break;
            }
        }
        public void Startup(int port)
        {
            this.localEndPoint = new IPEndPoint(IPAddress.Any, port);
            if (this.listenThread == null || this.listenThread.IsAlive == false)
            {
                this.listenThread = new Thread(new ThreadStart(TaskRunning));
                this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
            }
            switch (listenThread.ThreadState)
            {
                case System.Threading.ThreadState.Unstarted:
                    this.listenThread.Start();
                    runing = true;
                    break;
                case System.Threading.ThreadState.StopRequested:
                case System.Threading.ThreadState.AbortRequested:
                case System.Threading.ThreadState.Aborted:
                case System.Threading.ThreadState.Stopped:
                case System.Threading.ThreadState.Suspended:
                case System.Threading.ThreadState.SuspendRequested:
                    this.listenThread.Abort();
                    this.listenThread = new Thread(new ThreadStart(TaskRunning));
                    this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
                    this.listenThread.Start();
                    runing = true;
                    break;
                case System.Threading.ThreadState.Running:
                    runing = true;
                    break;
            }
        }
        public void Startup(string ipaddr, int port)
        {
            this.localEndPoint = new IPEndPoint(IPAddress.Parse(ipaddr), port);
            if (this.listenThread == null || this.listenThread.IsAlive == false)
            {
                this.listenThread = new Thread(new ThreadStart(TaskRunning));
                this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
            }
            switch (listenThread.ThreadState)
            {
                case System.Threading.ThreadState.Unstarted:
                    this.listenThread.Start();
                    runing = true;
                    break;
                case System.Threading.ThreadState.StopRequested:
                case System.Threading.ThreadState.AbortRequested:
                case System.Threading.ThreadState.Aborted:
                case System.Threading.ThreadState.Stopped:
                case System.Threading.ThreadState.Suspended:
                case System.Threading.ThreadState.SuspendRequested:
                    this.listenThread.Abort();
                    this.listenThread = new Thread(new ThreadStart(TaskRunning));
                    this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
                    this.listenThread.Start();
                    runing = true;
                    break;
                case System.Threading.ThreadState.Running:
                    runing = true;
                    break;
            }
        }
        public void Stop()
        {
            try
            {
                this.runing = false;
                switch (listenThread.ThreadState)
                {
                    case System.Threading.ThreadState.Unstarted:
                    case System.Threading.ThreadState.Aborted:
                    case System.Threading.ThreadState.Stopped:
                        break;
                    case System.Threading.ThreadState.StopRequested:
                    case System.Threading.ThreadState.AbortRequested:
                        Thread.Sleep(2000); // 让线程工作一段时间
                        break;
                    case System.Threading.ThreadState.Suspended:
                    case System.Threading.ThreadState.SuspendRequested:
                        this.listenThread.Abort();
                        break;
                    case System.Threading.ThreadState.Background:
                    case System.Threading.ThreadState.Running:
                        this.listenThread.Join();
                        break;
                }
                logBuffer.Enqueue(new LogContentV2(LogLevelV2.Infor, "UdpServer Stop Called."));
            }
            catch (Exception e)
            {
                logBuffer.Enqueue(new LogContentV2(LogLevelV2.Error, "UdpServer Stop Exception.", e));
            }

            System.GC.Collect();
            logBuffer.Enqueue(new LogContentV2(LogLevelV2.Infor, "UdpServer Stoped Called System.GC.Collect."));
        }
        private void TaskRunning()
        {
            Task.Run(() =>
            {
                try
                {
                    while (runing)
                    {
                        // 接收数据
                        this.receiveBytes = udpServer.Receive(ref localEndPoint);
                        logBuffer.Enqueue(new LogContentV2(LogLevelV2.Infor, $"Received {receiveBytes.Length} Bytes."));

                        //处理数据
                        HandleReceiveResposoneModel();

                        // 响应数据
                        if (sendBytes.Length > 0)
                        {
                            udpServer.Send(sendBytes, sendBytes.Length, localEndPoint);
                            logBuffer.Enqueue(new LogContentV2(LogLevelV2.Infor, $"Sented {receiveBytes.Length} Bytes."));
                        }
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                    logBuffer.Enqueue(new LogContentV2(LogLevelV2.Error, "Task.Run Receive Exception.", e));
                }
            });
        }

        private void HandleReceiveResposoneModel()
        {
            logBuffer.Enqueue(new LogContentV2(LogLevelV2.Infor, $"HandleReceiveResposoneModel"));
            //this.receiveBytes;
            //this.sendBytes;
            string sendMessage = "Message received";
            sendBytes = Encoding.UTF8.GetBytes(sendMessage);
        }
    }
    internal class Program
    {
        static void Main(string[] args)
        {
            UdpServer udpServer = new UdpServer();
            udpServer.Startup("127.0.0.1",8421);
            Console.WriteLine("Press any key to stop the server");
            Console.ReadKey();
            udpServer.Stop();
        }
    }
}
namespace Notify.Log
{
    public enum LogLevel
    {
        Trace = 0,
        Debug = 1,
        Information = 2,
        Statistic = 3,
        Warning = 4,
        Mistake = 6,    //轻微错误
        Exception = 5,
        Error = 7,      //逻辑错误
        Critical = 8,    //严重错误
        Fault = 9       //致命错误
    }
    public enum LogLevelV2
    {
        Infor = 2,
        Excep = 5,
        Error = 7,
    }

    //临时日志是写文本文件,这种操作在高并发程序里会造成程序崩溃
    public class TempLog
    {
        //注意只有一个线程写,不能多个线程同时写文件。
        static public void logging(List<NtLog> logbuf, string filepath = "./NotifyLog.log")
        {
            // 确保日志文件的目录存在  
            Directory.CreateDirectory(Path.GetDirectoryName(filepath));
            // 使用StreamWriter写入日志  
            using (StreamWriter writer = new StreamWriter(filepath, true)) // true表示追加模式  
            {
                //writer.WriteLine($"Log Entry: {DateTime.Now} - This is a test log entry.");
                // 这里可以添加更多的日志写入操作
                //foreach (NtLog log in logbuf)
                //{
                //    writer.WriteLine(log.ToString());
                //    移除已经写了的缓存
                //    logbuf.Remove(log);//迭代器安全问题
                //}
                for (int i = 0; i < logbuf.Count; i++)
                {
                    //#if DEBUG
                    //                    Console.WriteLine(logbuf[i].ToString());
                    //#endif
                    writer.WriteLine(logbuf[i].ToString());
                    logbuf.RemoveAt(i);
                }
            }
        }
        static public void logging(List<NtLog> logbuf)
        {
            string fileName = $"{DateTime.Now:yyyy-MM-dd}.log"; // 构建文件名,例如 "2023-04-01.log"  
            string fullPath = Path.Combine("./logs", fileName);
            // 确保日志文件的目录存在  
            Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
            // 使用StreamWriter写入日志  
            using (StreamWriter writer = new StreamWriter(fullPath, true)) // true表示追加模式  
            {
                //writer.WriteLine($"Log Entry: {DateTime.Now} - This is a test log entry.");
                // 这里可以添加更多的日志写入操作
                //foreach (NtLog log in logbuf)
                //{
                //    writer.WriteLine(log.ToString());
                //    移除已经写了的缓存
                //    logbuf.Remove(log);//迭代器安全问题
                //}
                for (int i = 0; i < logbuf.Count; i++)
                {
#if DEBUG
                    Console.WriteLine(logbuf[i].ToString());
#endif
                    writer.WriteLine(logbuf[i].ToString());
                    logbuf.RemoveAt(i);
                }
            }
        }

        static public void logging(string message, string logpath)
        {
            using (StreamWriter writer = new StreamWriter(logpath, true)) // true表示追加模式  
            {
                //string fileName = $"{DateTime.Now:yyyy-MM-dd}.log"; // 构建文件名,例如 "2023-04-01.log"  
                string content = $"{DateTime.Now:yyyy-MM-ddTHH:mm:ss} {message}";
                writer.WriteLine(content);
            }
        }
        static public void logging(string message)
        {
            string path = AppDomain.CurrentDomain.BaseDirectory;

            using (StreamWriter writer = new StreamWriter(path + "//TempLog.log", true)) // true表示追加模式  
            {
                //string fileName = $"{DateTime.Now:yyyy-MM-dd}.log"; // 构建文件名,例如 "2023-04-01.log"  
                string content = $"{DateTime.Now:yyyy-MM-ddTHH:mm:ss} {message}";
                writer.WriteLine(content);
            }
        }
    }
    public class LogContentV2
    {
        public DateTime Occurrence { get; set; }
        public LogLevelV2 LevelV2 { get; set; }
        public StackTrace Trace { get; set; }
        public string Message { get; set; }
        public LogContentV2() { }
        public LogContentV2(LogLevelV2 level, string message)
        {
            this.Occurrence = DateTime.Now;
            this.LevelV2 = level;
            this.Trace = new StackTrace(true);//捕捉当前堆栈
            this.Message = message;
        }
        public LogContentV2(LogLevelV2 level, string message, Exception e)
        {
            this.Occurrence = DateTime.Now;
            this.LevelV2 = level;
            this.Trace = new StackTrace(e, true);//捕捉当前异常堆栈堆栈
            this.Message = message;
        }
        public override string ToString()
        {
            return $"{Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.ffff")} {LevelV2.ToString()}:{Message}";//因为ffff会确保输出始终是4位数字,不足的部分用零填充。
        }
    }
    public class LogContent
    {
        public DateTime Occurrence { get; set; }
        public LogLevel Level { get; set; }
        public StackTrace Trace { get; set; }
        public string Message { get; set; }

        public LogContent() { }
        public LogContent(LogLevel level, string message)
        {
            this.Occurrence = DateTime.Now;
            this.Level = level;
            this.Trace = new StackTrace(true);//捕捉当前堆栈
            this.Message = message;
        }
        public LogContent(LogLevel level, string message, Exception e)
        {
            this.Occurrence = DateTime.Now;
            this.Level = level;
            this.Trace = new StackTrace(e, true);//捕捉当前异常堆栈堆栈
            this.Message = message;
        }
        public override string ToString()
        {
            //string tmp = Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF") + " " + Level.ToString() + " " + Message + "\n";
            //string tmp = $"{Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF")} {Level.ToString()} {Message}";
            //return tmp;
            return $"{Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF")} {Level.ToString()}:{Message}";
        }
    }
    public class LogContentX
    {
        public DateTime Occurrence { get; set; }
        public LogLevel Level { get; set; }
        public StackTrace Trace { get; set; }
        public string Message { get; set; }

        public LogContentX() { }
        public LogContentX(LogLevel level, string message) { this.SetLog(level, message); }
        public LogContentX(LogLevel level, string message, Exception e) { this.SetLog(level, message, e); }
        public void SetLog(LogLevel level, string message)
        {
            this.Occurrence = DateTime.Now;
            this.Level = level;
            this.Trace = new StackTrace(true);//捕捉当前堆栈
            this.Message = message;
        }
        public void SetLog(LogLevel level, string message, Exception e)
        {
            this.Occurrence = DateTime.Now;
            this.Level = level;
            this.Trace = new StackTrace(e, true);//捕捉当前异常堆栈堆栈
            this.Message = message;
        }
        public override string ToString()
        {
            string tmp = Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF") + " " + Level.ToString() + " " + Message + "\n";

            return tmp;
        }
        public string TraceDetail()
        {
            string tmp = Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF") + " " + Level.ToString() + " " + Message + "\n";
            tmp += this.Trace.ToString() + "\r\n";
            //StackFrame sf = Trace.GetFrame(0); 
            //tmp += $" Method: {sf.GetMethod()}\r\n";
            //$" File: {sf.GetFileName()}\r\n" +
            //$" Line Number: {sf.GetFileLineNumber()}\r\n";

            return tmp;
        }
        public static string TraceDetail(LogContent log)
        {
            string tmp = log.Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF") + " " + " " + log.Level.ToString() + ":" + log.Message + "\n";
            tmp += log.Trace.ToString() + "\r\n";
            //StackFrame sf = Trace.GetFrame(0); 
            //tmp += $" Method: {sf.GetMethod()}\r\n";
            //$" File: {sf.GetFileName()}\r\n" +
            //$" Line Number: {sf.GetFileLineNumber()}\r\n";

            return tmp;
        }
        public string TraceTopFrame()
        {
            return this.Trace.GetFrame(0).ToString();
        }
        public StackFrame TraceTopStackFrame()
        {
            return Trace.GetFrame(0);
        }
        public StackFrame TraceBottomStackFrame()
        {
            return Trace.GetFrame(this.Trace.FrameCount - 1);
        }
        public int GetSize()
        {
            //在safe环境中无法使用sizeof(DateTime),sizeof(DateTime)用8字节代替
            // Each character in a string is 2 bytes (UTF-16 encoding).
            int total = sizeof(LogLevel) + this.Message.Length * 2 + 8;
            for (int i = 0; i < this.Trace.FrameCount; i++)
            {
                StackFrame sf = this.Trace.GetFrame(i);
                //sf.GetFileLineNumber();sf.GetFileName(); sf.GetMethod().Name; 
                total += sf.ToString().Length * 2;
            }
            return total;
        }
        public static int GetSize(LogContent log)
        {
            //在safe环境中无法使用sizeof(DateTime),sizeof(DateTime)用8字节代替
            // Each character in a string is 2 bytes (UTF-16 encoding).
            int total = sizeof(LogLevel) + log.Message.Length * 2 + 8;
            for (int i = 0; i < log.Trace.FrameCount; i++)
            {
                StackFrame sf = log.Trace.GetFrame(i);
                //sf.GetFileLineNumber();sf.GetFileName(); sf.GetMethod().Name; 
                total += sf.ToString().Length * 2;
            }
            return total;
        }
    }

    public class LogBuffer
    {
        protected List<LogContent> buf = new List<LogContent>();
        public List<LogContent> Buffer { get { return buf; } }

        public LogBuffer()
        {
            buf = new List<LogContent>();
        }
        public LogBuffer(List<LogContent> buf)
        {
            this.buf = buf;
        }
        public void Insert(LogContent log)
        {
            this.buf.Add(log);
        }
        public void Insert(LogBuffer log)
        {
            foreach (var item in log.Buffer)
            {
                this.buf.Add(item);
            }
        }
        public int LogSize()
        {
            int size = 0;
            foreach (LogContent cnt in this.buf)
            {
                size += LogContentX.GetSize(cnt);
            }
            return size;
        }
    }
    public class LogBufQuery
    {
        public List<LogContent> Buffer { get; set; }

        public void TimeOrderAsc()
        {
            Buffer.Sort((x, y) => x.Occurrence.CompareTo(y.Occurrence));
        }
        public void TimeOrderDsc()
        {
            Buffer.Sort((x, y) => y.Occurrence.CompareTo(x.Occurrence));
        }
        public List<LogContent> FilterByLoglevel(LogLevel loglevel)
        {
            return Buffer.FindAll(log => log.Level == loglevel);
        }
    }

    public struct logstatics
    {
        public string item;
        public string value;
        public long Timestamp;

        // 将 UNIX 时间戳转换为 DateTime
        //DateTime dateTime = DateTimeOffset.FromUnixTimeSeconds(Timestamp).DateTime;
        public DateTime FromUnixTime()
        {
            return DateTimeOffset.FromUnixTimeSeconds(Timestamp).DateTime;
        }

    }


    public class TotalAccessSattistic
    {
        private ulong totalAccess;
        /// <summary>
        /// 总访问量
        /// </summary>
        public ulong TotalAccess
        {
            get
            {
                return this.totalAccess;
            }
        }
        private void Reset()
        { this.totalAccess = 0; }
        public void StasticAccess(List<LogContent> buf, string flagstr = "HandleClientComm")
        {
            foreach (var cnt in buf)
            {
                if (cnt.Message == flagstr)
                    this.totalAccess++;
            }
        }
    }

    //将日志写成文本文件,注意在多线程环境下要排除线程互斥。
    public class NtLog
    {
        //private Queue<LogBuffer> Buff = new Queue<LogBuffer>();
        private Queue<LogContent> buffer = new Queue<LogContent>();
        public string LogPath { get; }
        private string curfilepath = string.Empty;
        private string errorLgFile = string.Empty;  //定义从Exception到Fault这5个层级为Error
        private Task task;  //不要删除,多线程写日志时会用到
        private Stopwatch watcher = new Stopwatch();
        private long maxms, minms, lastms;
        private volatile bool IsWriting = false;
        public bool Writing { get { return IsWriting; } }
        /// <summary>
        /// 平均耗时
        /// </summary>
        public long AverageConsum
        {
            get
            {
                return (maxms + minms + lastms) / 3;
            }
        }
        public NtLog()
        {
            this.LogPath = AppDomain.CurrentDomain.BaseDirectory;


            创建日志文件夹
            this.LogPath = CreateLogDirectory();
            MakeLogFileName();
            maxms = minms = lastms = 0;
        }
        public void Enqueue(LogContent log)
        {
            this.buffer.Enqueue(log);
        }
        public void Enqueue(List<LogContent> logs)
        {
            foreach (LogContent log in logs)
            {
                this.buffer.Enqueue(log);
            }
        }
        public void Enqueue(LogBuffer logbuf)
        {
            foreach (LogContent log in logbuf.Buffer)
            {
                this.buffer.Enqueue(log);
            }
        }
        public void OnLogging(List<LogContent> logs)
        {
            //#if DEBUG
            //            TempLog.logging($"查看原始数据。{logs.Count} ");//{logs.First().Message}
            //#endif
            //this.Buff.Enqueue(new LogBuffer(logs));
            this.Enqueue(logs);

            this.UpdatePathFileName();
            if (this.IsWriting == false && this.buffer.Count > 0)
            {
                //LogBuffer Temp = this.Buff.Dequeue();
                //while (this.Buff.Count > 0)
                //{
                //    Temp.Insert(this.Buff.Dequeue());
                //}
                WriteLogByThreadV4(this.buffer);
            }

        }
        public void OnLogging(Queue<LogContent> logs)
        {
            for (int i = 0; i < logs.Count; i++)
            {
                this.buffer.Enqueue(logs.Dequeue());
            }

            this.UpdatePathFileName();
            if (this.IsWriting == false && this.buffer.Count > 0)
            {
                //LogBuffer Temp = this.Buff.Dequeue();
                //while (this.Buff.Count > 0)
                //{
                //    Temp.Insert(this.Buff.Dequeue());
                //}
                WriteLogByThreadV4(this.buffer);
            }
        }
        public static string CreateLogDirectory()
        {
            string path = AppDomain.CurrentDomain.BaseDirectory;

            // 获取当前应用程序域的名称(通常是程序集名称)
            string assemblyName = AppDomain.CurrentDomain.FriendlyName;

            // 去掉路径和扩展名,只保留文件名
            assemblyName = Path.GetFileNameWithoutExtension(assemblyName);

            // 组合成完整的路径
            path = System.IO.Path.Combine(path, assemblyName + "Log");
            //TempLog.logging(path);
            //创建日志文件夹
            Directory.CreateDirectory(path);
            return path;
        }
        public void UpdatePathFileName()
        {
            string path = AppDomain.CurrentDomain.BaseDirectory;

            // 获取当前应用程序域的名称(通常是程序集名称)
            string assemblyName = AppDomain.CurrentDomain.FriendlyName;

            // 去掉路径和扩展名,只保留文件名
            assemblyName = Path.GetFileNameWithoutExtension(assemblyName);

            // 组合成完整的路径
            path = System.IO.Path.Combine(path, assemblyName + "Log");
            //TempLog.logging(path);
            //创建日志文件夹
            Directory.CreateDirectory(path);

            string dn = DateTime.Now.ToString("yyyy-MM-dd");

            this.curfilepath = Path.Combine(this.LogPath, assemblyName + dn + ".log");
            this.errorLgFile = Path.Combine(this.LogPath, assemblyName + dn + "err.log");
        }
        public void MakeLogFileName()
        {
            // 获取当前应用程序域的名称(通常是程序集名称)
            string assemblyName = AppDomain.CurrentDomain.FriendlyName;

            // 去掉路径和扩展名,只保留文件名
            assemblyName = Path.GetFileNameWithoutExtension(assemblyName);

            string dn = DateTime.Now.ToString("yyyy-MM-dd");

            this.curfilepath = Path.Combine(this.LogPath, assemblyName + dn + ".log");
            this.errorLgFile = Path.Combine(this.LogPath, assemblyName + dn + "err.log");
        }

        public void WriteLogFile()
        {
            using (StreamWriter writer = new StreamWriter(this.curfilepath, true)) // true表示追加模式  
            {
                foreach (var cnt in this.buffer)
                {
                    writer.WriteLine(cnt.ToString());
                }
            }
        }
        public void WriteErrorLog()
        {
            using (StreamWriter writer = new StreamWriter(this.errorLgFile, true)) // true表示追加模式  
            {
                foreach (var cnt in this.buffer)
                {
                    if (cnt.Level >= LogLevel.Warning)
                        writer.WriteLine(LogContentX.TraceDetail(cnt));
                }

            }
        }

        //发现它仍然阻塞主线程
        //注意只有一个线程写,不能多个线程同时写文件。
        //请注意,Buffer.Remove(cnt) 在循环中可能会导致问题,因为从集合中移除元素会改变集合的大小,从而可能导致迭代器失效。为了避免这个问题,可以先收集需要删除的元素,然后在循环结束后统一删除它们。
        public void WriteLogByThread(LogBuffer logs)
        {
            this.watcher.Start();
            this.IsWriting = true;
            //#if DEBUG
            //            TempLog.logging($"BeofreWriteLog。{this.curfilepath} {this.errorLgFile}");
            //#endif
            //this.WriteLogFile
            // 使用Task.Run在后台线程中执行文件写入操作
            this.task = Task.Run(() =>
            {
                //FileStream可以设置成独享锁定模式,防止 线程互斥
                using (FileStream fs1 = new FileStream(this.curfilepath, FileMode.Append, FileAccess.Write, FileShare.None),
                        fs2 = new FileStream(this.errorLgFile, FileMode.Append, FileAccess.Write, FileShare.None))
                {
                    using (StreamWriter writer = new StreamWriter(fs1), writer2 = new StreamWriter(fs2))
                    {
                        foreach (var cnt in logs.Buffer)
                        {
                            writer.WriteLine(cnt.ToString());

                            if (cnt.Level >= LogLevel.Warning)
                                writer2.WriteLine(LogContentX.TraceDetail(cnt));
                        }
                    }
                }
                //Buffer没有上锁是希望它尽快完成操作,但有风险
            });
            this.watcher.Stop();
            this.IsWriting = false;
            if (this.lastms > 0 && this.lastms > this.maxms)
            {
                this.maxms = this.lastms;
            }
            if (this.lastms > 0 && this.minms == 0)
                this.minms = this.lastms;
            if (this.lastms > 0 && this.lastms < this.minms)
            {
                this.minms = this.lastms;
            }
            this.lastms = watcher.ElapsedMilliseconds;
        }

        //如果没有errlog就不写
        public void WriteLogByThreadV2(LogBuffer logs)
        {
            this.watcher.Start();
            this.IsWriting = true;
            Queue<LogContent> errlogs = new Queue<LogContent>();
            //#if DEBUG
            //            TempLog.logging($"BeofreWriteLog。{this.curfilepath} {this.errorLgFile}");
            //#endif
            //this.WriteLogFile
            // 使用Task.Run在后台线程中执行文件写入操作
            this.task = Task.Run(() =>
            {
                //FileStream可以设置成独享锁定模式,防止 线程互斥
                using (FileStream fs1 = new FileStream(this.curfilepath, FileMode.Append, FileAccess.Write, FileShare.None))
                {
                    using (StreamWriter writer = new StreamWriter(fs1))
                    {
                        foreach (var cnt in logs.Buffer)
                        {
                            writer.WriteLine(cnt.ToString());

                            if (cnt.Level >= LogLevel.Warning)
                                errlogs.Enqueue(cnt);
                        }
                    }
                }
                if (errlogs.Count > 0)
                {
                    using (FileStream fs2 = new FileStream(this.errorLgFile, FileMode.Append, FileAccess.Write, FileShare.None))
                    {
                        using (StreamWriter writer2 = new StreamWriter(fs2))
                        {
                            for (int i = 0; i < errlogs.Count; i++)
                            {
                                writer2.WriteLine(errlogs.Dequeue().ToString());
                            }
                        }
                    }
                }
                //Buffer没有上锁是希望它尽快完成操作,但有风险
            });
            this.watcher.Stop();
            this.IsWriting = false;
            if (this.lastms > 0 && this.lastms > this.maxms)
            {
                this.maxms = this.lastms;
            }
            if (this.lastms > 0 && this.minms == 0)
                this.minms = this.lastms;
            if (this.lastms > 0 && this.lastms < this.minms)
            {
                this.minms = this.lastms;
            }
            this.lastms = watcher.ElapsedMilliseconds;
        }
        public void WriteLogByThreadV3(Queue<LogContent> queue)
        {
            this.watcher.Start();
            this.IsWriting = true;
            Queue<LogContent> errlogs = new Queue<LogContent>();
            //#if DEBUG
            //            TempLog.logging($"BeofreWriteLog。{this.curfilepath} {this.errorLgFile}");
            //#endif
            //this.WriteLogFile
            // 使用Task.Run在后台线程中执行文件写入操作
            this.task = Task.Run(() =>
            {
                //FileStream可以设置成独享锁定模式,防止 线程互斥
                using (FileStream fs1 = new FileStream(this.curfilepath, FileMode.Append, FileAccess.Write, FileShare.None))
                {
                    using (StreamWriter writer = new StreamWriter(fs1))
                    {
                        //foreach (var cnt in queue)
                        //{
                        //    writer.WriteLine(cnt.ToString());
                        //    ;
                        //    if (cnt.Level >= LogLevel.Warning)
                        //        errlogs.Enqueue(cnt);
                        //}
                        while (queue.Count > 0)
                        {
                            var tmp = queue.Dequeue();
                            writer.WriteLine(tmp.ToString());
                            if (tmp.Level >= LogLevel.Warning)
                                errlogs.Enqueue(tmp);
                        }
                    }
                }
                if (errlogs.Count > 0)
                {
                    using (FileStream fs2 = new FileStream(this.errorLgFile, FileMode.Append, FileAccess.Write, FileShare.None))
                    {
                        using (StreamWriter writer2 = new StreamWriter(fs2))
                        {
                            for (int i = 0; i < errlogs.Count; i++)
                            {
                                writer2.WriteLine(errlogs.Dequeue().ToString());
                            }
                        }
                    }
                }
                //Buffer没有上锁是希望它尽快完成操作,但有风险
            });
            this.watcher.Stop();
            this.IsWriting = false;
            if (this.lastms > 0 && this.lastms > this.maxms)
            {
                this.maxms = this.lastms;
            }
            if (this.lastms > 0 && this.minms == 0)
                this.minms = this.lastms;
            if (this.lastms > 0 && this.lastms < this.minms)
            {
                this.minms = this.lastms;
            }
            this.lastms = watcher.ElapsedMilliseconds;
        }
        public void WriteLogByThreadV4(Queue<LogContent> queue)
        {
            this.watcher.Start();
            this.IsWriting = true;
            Queue<LogContent> errlogs = new Queue<LogContent>();
            //#if DEBUG
            //            TempLog.logging($"BeofreWriteLog。{this.curfilepath} {this.errorLgFile}");
            //#endif
            //this.WriteLogFile
            // 使用Task.Run在后台线程中执行文件写入操作
            this.task = Task.Run(() =>
            {
                //FileStream可以设置成独享锁定模式,防止 线程互斥
                using (FileStream fs1 = new FileStream(this.curfilepath, FileMode.Append, FileAccess.Write, FileShare.None))
                {
                    using (StreamWriter writer = new StreamWriter(fs1))
                    {
                        //foreach (var cnt in queue)
                        //{
                        //    writer.WriteLine(cnt.ToString());
                        //    ;
                        //    if (cnt.Level >= LogLevel.Warning)
                        //        errlogs.Enqueue(cnt);
                        //}
                        while (queue.Count > 0)
                        {
                            var tmp = queue.Dequeue();
                            writer.WriteLine(tmp.ToString());
                            if (tmp.Level >= LogLevel.Warning)
                                errlogs.Enqueue(tmp);
                        }
                    }
                }
                if (errlogs.Count > 0)
                {
                    using (FileStream fs2 = new FileStream(this.errorLgFile, FileMode.Append, FileAccess.Write, FileShare.None))
                    {
                        using (StreamWriter writer2 = new StreamWriter(fs2))
                        {
                            for (int i = 0; i < errlogs.Count; i++)
                            {
                                writer2.WriteLine(LogContentX.TraceDetail(errlogs.Dequeue()));
                            }
                        }
                    }
                }
                //Buffer没有上锁是希望它尽快完成操作,但有风险
            });
            this.watcher.Stop();
            this.IsWriting = false;
            if (this.lastms > 0 && this.lastms > this.maxms)
            {
                this.maxms = this.lastms;
            }
            if (this.lastms > 0 && this.minms == 0)
                this.minms = this.lastms;
            if (this.lastms > 0 && this.lastms < this.minms)
            {
                this.minms = this.lastms;
            }
            this.lastms = watcher.ElapsedMilliseconds;
        }
    }
}

Udp客户端:

cs 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
using System.IO;
using Notify.Log;

namespace UdpSer
{
    public class UdpServer
    {
        // 创建UDP端点,并绑定到本地端口
        IPEndPoint localEndPoint;
        // 创建UDP套接字
        private UdpClient udpServer = new UdpClient();
        private volatile bool runing = false;
        private byte[] receiveBytes = new byte[2048];
        private byte[] sendBytes = new byte[2048];
        private Queue<LogContentV2> logBuffer = new Queue<LogContentV2>();
        private Thread listenThread;
        public int LogBufferCount { get { return this.logBuffer.Count; } }
        public LogContentV2 Log { get { return this.logBuffer.Dequeue(); } }
        public UdpServer()
        {
            // 创建UDP端点,并绑定到本地端口
            localEndPoint = new IPEndPoint(IPAddress.Any, 8421);
            // 创建UDP套接字
            udpServer = new UdpClient(localEndPoint);
            if (this.listenThread == null || this.listenThread.IsAlive == false)
            {
                this.listenThread = new Thread(new ThreadStart(TaskRunning));
                this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
            }
            logBuffer.Enqueue(new LogContentV2(LogLevelV2.Infor, "UdpServer default constructed."));
        }
        public UdpServer(int port = 8421)
        {
            // 创建UDP端点,并绑定到本地端口
            localEndPoint = new IPEndPoint(IPAddress.Any, port);
            // 创建UDP套接字
            udpServer = new UdpClient(localEndPoint);
            if (this.listenThread == null || this.listenThread.IsAlive == false)
            {
                this.listenThread = new Thread(new ThreadStart(TaskRunning));
                this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
            }

            logBuffer.Enqueue(new LogContentV2(LogLevelV2.Infor, "UdpServer constructed."));
        }
        public void Startup()
        {
            this.localEndPoint = new IPEndPoint(IPAddress.Any, 8421);
            if (this.listenThread == null || this.listenThread.IsAlive == false)
            {
                this.listenThread = new Thread(new ThreadStart(TaskRunning));
                this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
            }
            switch (listenThread.ThreadState)
            {
                case System.Threading.ThreadState.Unstarted:
                    this.listenThread.Start();
                    runing = true;
                    break;
                case System.Threading.ThreadState.StopRequested:
                case System.Threading.ThreadState.AbortRequested:
                case System.Threading.ThreadState.Aborted:
                case System.Threading.ThreadState.Stopped:
                case System.Threading.ThreadState.Suspended:
                case System.Threading.ThreadState.SuspendRequested:
                    this.listenThread.Abort();
                    this.listenThread = new Thread(new ThreadStart(TaskRunning));
                    this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
                    this.listenThread.Start();
                    runing = true;
                    break;
                case System.Threading.ThreadState.Running:
                    runing = true;
                    break;
            }
        }
        public void Startup(int port)
        {
            this.localEndPoint = new IPEndPoint(IPAddress.Any, port);
            if (this.listenThread == null || this.listenThread.IsAlive == false)
            {
                this.listenThread = new Thread(new ThreadStart(TaskRunning));
                this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
            }
            switch (listenThread.ThreadState)
            {
                case System.Threading.ThreadState.Unstarted:
                    this.listenThread.Start();
                    runing = true;
                    break;
                case System.Threading.ThreadState.StopRequested:
                case System.Threading.ThreadState.AbortRequested:
                case System.Threading.ThreadState.Aborted:
                case System.Threading.ThreadState.Stopped:
                case System.Threading.ThreadState.Suspended:
                case System.Threading.ThreadState.SuspendRequested:
                    this.listenThread.Abort();
                    this.listenThread = new Thread(new ThreadStart(TaskRunning));
                    this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
                    this.listenThread.Start();
                    runing = true;
                    break;
                case System.Threading.ThreadState.Running:
                    runing = true;
                    break;
            }
        }
        public void Startup(string ipaddr, int port)
        {
            this.localEndPoint = new IPEndPoint(IPAddress.Parse(ipaddr), port);
            if (this.listenThread == null || this.listenThread.IsAlive == false)
            {
                this.listenThread = new Thread(new ThreadStart(TaskRunning));
                this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
            }
            switch (listenThread.ThreadState)
            {
                case System.Threading.ThreadState.Unstarted:
                    this.listenThread.Start();
                    runing = true;
                    break;
                case System.Threading.ThreadState.StopRequested:
                case System.Threading.ThreadState.AbortRequested:
                case System.Threading.ThreadState.Aborted:
                case System.Threading.ThreadState.Stopped:
                case System.Threading.ThreadState.Suspended:
                case System.Threading.ThreadState.SuspendRequested:
                    this.listenThread.Abort();
                    this.listenThread = new Thread(new ThreadStart(TaskRunning));
                    this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
                    this.listenThread.Start();
                    runing = true;
                    break;
                case System.Threading.ThreadState.Running:
                    runing = true;
                    break;
            }
        }
        public void Stop()
        {
            try
            {
                this.runing = false;
                switch (listenThread.ThreadState)
                {
                    case System.Threading.ThreadState.Unstarted:
                    case System.Threading.ThreadState.Aborted:
                    case System.Threading.ThreadState.Stopped:
                        break;
                    case System.Threading.ThreadState.StopRequested:
                    case System.Threading.ThreadState.AbortRequested:
                        Thread.Sleep(2000); // 让线程工作一段时间
                        break;
                    case System.Threading.ThreadState.Suspended:
                    case System.Threading.ThreadState.SuspendRequested:
                        this.listenThread.Abort();
                        break;
                    case System.Threading.ThreadState.Background:
                    case System.Threading.ThreadState.Running:
                        this.listenThread.Join();
                        break;
                }
                logBuffer.Enqueue(new LogContentV2(LogLevelV2.Infor, "UdpServer Stop Called."));
            }
            catch (Exception e)
            {
                logBuffer.Enqueue(new LogContentV2(LogLevelV2.Error, "UdpServer Stop Exception.", e));
            }

            System.GC.Collect();
            logBuffer.Enqueue(new LogContentV2(LogLevelV2.Infor, "UdpServer Stoped Called System.GC.Collect."));
        }
        private void TaskRunning()
        {
            Task.Run(() =>
            {
                try
                {
                    while (runing)
                    {
                        // 接收数据
                        this.receiveBytes = udpServer.Receive(ref localEndPoint);
                        logBuffer.Enqueue(new LogContentV2(LogLevelV2.Infor, $"Received {receiveBytes.Length} Bytes."));

                        //处理数据
                        HandleReceiveResposoneModel();

                        // 响应数据
                        if (sendBytes.Length > 0)
                        {
                            udpServer.Send(sendBytes, sendBytes.Length, localEndPoint);
                            logBuffer.Enqueue(new LogContentV2(LogLevelV2.Infor, $"Sented {receiveBytes.Length} Bytes."));
                        }
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                    logBuffer.Enqueue(new LogContentV2(LogLevelV2.Error, "Task.Run Receive Exception.", e));
                }
            });
        }

        private void HandleReceiveResposoneModel()
        {
            logBuffer.Enqueue(new LogContentV2(LogLevelV2.Infor, $"HandleReceiveResposoneModel"));
            //this.receiveBytes;
            //this.sendBytes;
            string sendMessage = "Message received";
            sendBytes = Encoding.UTF8.GetBytes(sendMessage);
        }
    }
    internal class Program
    {
        static void Main(string[] args)
        {
            UdpServer udpServer = new UdpServer();
            udpServer.Startup("127.0.0.1",8421);
            Console.WriteLine("Press any key to stop the server");
            Console.ReadKey();
            udpServer.Stop();
        }
    }
}
namespace Notify.Log
{
    public enum LogLevel
    {
        Trace = 0,
        Debug = 1,
        Information = 2,
        Statistic = 3,
        Warning = 4,
        Mistake = 6,    //轻微错误
        Exception = 5,
        Error = 7,      //逻辑错误
        Critical = 8,    //严重错误
        Fault = 9       //致命错误
    }
    public enum LogLevelV2
    {
        Infor = 2,
        Excep = 5,
        Error = 7,
    }

    //临时日志是写文本文件,这种操作在高并发程序里会造成程序崩溃
    public class TempLog
    {
        //注意只有一个线程写,不能多个线程同时写文件。
        static public void logging(List<NtLog> logbuf, string filepath = "./NotifyLog.log")
        {
            // 确保日志文件的目录存在  
            Directory.CreateDirectory(Path.GetDirectoryName(filepath));
            // 使用StreamWriter写入日志  
            using (StreamWriter writer = new StreamWriter(filepath, true)) // true表示追加模式  
            {
                //writer.WriteLine($"Log Entry: {DateTime.Now} - This is a test log entry.");
                // 这里可以添加更多的日志写入操作
                //foreach (NtLog log in logbuf)
                //{
                //    writer.WriteLine(log.ToString());
                //    移除已经写了的缓存
                //    logbuf.Remove(log);//迭代器安全问题
                //}
                for (int i = 0; i < logbuf.Count; i++)
                {
                    //#if DEBUG
                    //                    Console.WriteLine(logbuf[i].ToString());
                    //#endif
                    writer.WriteLine(logbuf[i].ToString());
                    logbuf.RemoveAt(i);
                }
            }
        }
        static public void logging(List<NtLog> logbuf)
        {
            string fileName = $"{DateTime.Now:yyyy-MM-dd}.log"; // 构建文件名,例如 "2023-04-01.log"  
            string fullPath = Path.Combine("./logs", fileName);
            // 确保日志文件的目录存在  
            Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
            // 使用StreamWriter写入日志  
            using (StreamWriter writer = new StreamWriter(fullPath, true)) // true表示追加模式  
            {
                //writer.WriteLine($"Log Entry: {DateTime.Now} - This is a test log entry.");
                // 这里可以添加更多的日志写入操作
                //foreach (NtLog log in logbuf)
                //{
                //    writer.WriteLine(log.ToString());
                //    移除已经写了的缓存
                //    logbuf.Remove(log);//迭代器安全问题
                //}
                for (int i = 0; i < logbuf.Count; i++)
                {
#if DEBUG
                    Console.WriteLine(logbuf[i].ToString());
#endif
                    writer.WriteLine(logbuf[i].ToString());
                    logbuf.RemoveAt(i);
                }
            }
        }

        static public void logging(string message, string logpath)
        {
            using (StreamWriter writer = new StreamWriter(logpath, true)) // true表示追加模式  
            {
                //string fileName = $"{DateTime.Now:yyyy-MM-dd}.log"; // 构建文件名,例如 "2023-04-01.log"  
                string content = $"{DateTime.Now:yyyy-MM-ddTHH:mm:ss} {message}";
                writer.WriteLine(content);
            }
        }
        static public void logging(string message)
        {
            string path = AppDomain.CurrentDomain.BaseDirectory;

            using (StreamWriter writer = new StreamWriter(path + "//TempLog.log", true)) // true表示追加模式  
            {
                //string fileName = $"{DateTime.Now:yyyy-MM-dd}.log"; // 构建文件名,例如 "2023-04-01.log"  
                string content = $"{DateTime.Now:yyyy-MM-ddTHH:mm:ss} {message}";
                writer.WriteLine(content);
            }
        }
    }
    public class LogContentV2
    {
        public DateTime Occurrence { get; set; }
        public LogLevelV2 LevelV2 { get; set; }
        public StackTrace Trace { get; set; }
        public string Message { get; set; }
        public LogContentV2() { }
        public LogContentV2(LogLevelV2 level, string message)
        {
            this.Occurrence = DateTime.Now;
            this.LevelV2 = level;
            this.Trace = new StackTrace(true);//捕捉当前堆栈
            this.Message = message;
        }
        public LogContentV2(LogLevelV2 level, string message, Exception e)
        {
            this.Occurrence = DateTime.Now;
            this.LevelV2 = level;
            this.Trace = new StackTrace(e, true);//捕捉当前异常堆栈堆栈
            this.Message = message;
        }
        public override string ToString()
        {
            return $"{Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.ffff")} {LevelV2.ToString()}:{Message}";//因为ffff会确保输出始终是4位数字,不足的部分用零填充。
        }
    }
    public class LogContent
    {
        public DateTime Occurrence { get; set; }
        public LogLevel Level { get; set; }
        public StackTrace Trace { get; set; }
        public string Message { get; set; }

        public LogContent() { }
        public LogContent(LogLevel level, string message)
        {
            this.Occurrence = DateTime.Now;
            this.Level = level;
            this.Trace = new StackTrace(true);//捕捉当前堆栈
            this.Message = message;
        }
        public LogContent(LogLevel level, string message, Exception e)
        {
            this.Occurrence = DateTime.Now;
            this.Level = level;
            this.Trace = new StackTrace(e, true);//捕捉当前异常堆栈堆栈
            this.Message = message;
        }
        public override string ToString()
        {
            //string tmp = Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF") + " " + Level.ToString() + " " + Message + "\n";
            //string tmp = $"{Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF")} {Level.ToString()} {Message}";
            //return tmp;
            return $"{Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF")} {Level.ToString()}:{Message}";
        }
    }
    public class LogContentX
    {
        public DateTime Occurrence { get; set; }
        public LogLevel Level { get; set; }
        public StackTrace Trace { get; set; }
        public string Message { get; set; }

        public LogContentX() { }
        public LogContentX(LogLevel level, string message) { this.SetLog(level, message); }
        public LogContentX(LogLevel level, string message, Exception e) { this.SetLog(level, message, e); }
        public void SetLog(LogLevel level, string message)
        {
            this.Occurrence = DateTime.Now;
            this.Level = level;
            this.Trace = new StackTrace(true);//捕捉当前堆栈
            this.Message = message;
        }
        public void SetLog(LogLevel level, string message, Exception e)
        {
            this.Occurrence = DateTime.Now;
            this.Level = level;
            this.Trace = new StackTrace(e, true);//捕捉当前异常堆栈堆栈
            this.Message = message;
        }
        public override string ToString()
        {
            string tmp = Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF") + " " + Level.ToString() + " " + Message + "\n";

            return tmp;
        }
        public string TraceDetail()
        {
            string tmp = Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF") + " " + Level.ToString() + " " + Message + "\n";
            tmp += this.Trace.ToString() + "\r\n";
            //StackFrame sf = Trace.GetFrame(0); 
            //tmp += $" Method: {sf.GetMethod()}\r\n";
            //$" File: {sf.GetFileName()}\r\n" +
            //$" Line Number: {sf.GetFileLineNumber()}\r\n";

            return tmp;
        }
        public static string TraceDetail(LogContent log)
        {
            string tmp = log.Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF") + " " + " " + log.Level.ToString() + ":" + log.Message + "\n";
            tmp += log.Trace.ToString() + "\r\n";
            //StackFrame sf = Trace.GetFrame(0); 
            //tmp += $" Method: {sf.GetMethod()}\r\n";
            //$" File: {sf.GetFileName()}\r\n" +
            //$" Line Number: {sf.GetFileLineNumber()}\r\n";

            return tmp;
        }
        public string TraceTopFrame()
        {
            return this.Trace.GetFrame(0).ToString();
        }
        public StackFrame TraceTopStackFrame()
        {
            return Trace.GetFrame(0);
        }
        public StackFrame TraceBottomStackFrame()
        {
            return Trace.GetFrame(this.Trace.FrameCount - 1);
        }
        public int GetSize()
        {
            //在safe环境中无法使用sizeof(DateTime),sizeof(DateTime)用8字节代替
            // Each character in a string is 2 bytes (UTF-16 encoding).
            int total = sizeof(LogLevel) + this.Message.Length * 2 + 8;
            for (int i = 0; i < this.Trace.FrameCount; i++)
            {
                StackFrame sf = this.Trace.GetFrame(i);
                //sf.GetFileLineNumber();sf.GetFileName(); sf.GetMethod().Name; 
                total += sf.ToString().Length * 2;
            }
            return total;
        }
        public static int GetSize(LogContent log)
        {
            //在safe环境中无法使用sizeof(DateTime),sizeof(DateTime)用8字节代替
            // Each character in a string is 2 bytes (UTF-16 encoding).
            int total = sizeof(LogLevel) + log.Message.Length * 2 + 8;
            for (int i = 0; i < log.Trace.FrameCount; i++)
            {
                StackFrame sf = log.Trace.GetFrame(i);
                //sf.GetFileLineNumber();sf.GetFileName(); sf.GetMethod().Name; 
                total += sf.ToString().Length * 2;
            }
            return total;
        }
    }

    public class LogBuffer
    {
        protected List<LogContent> buf = new List<LogContent>();
        public List<LogContent> Buffer { get { return buf; } }

        public LogBuffer()
        {
            buf = new List<LogContent>();
        }
        public LogBuffer(List<LogContent> buf)
        {
            this.buf = buf;
        }
        public void Insert(LogContent log)
        {
            this.buf.Add(log);
        }
        public void Insert(LogBuffer log)
        {
            foreach (var item in log.Buffer)
            {
                this.buf.Add(item);
            }
        }
        public int LogSize()
        {
            int size = 0;
            foreach (LogContent cnt in this.buf)
            {
                size += LogContentX.GetSize(cnt);
            }
            return size;
        }
    }
    public class LogBufQuery
    {
        public List<LogContent> Buffer { get; set; }

        public void TimeOrderAsc()
        {
            Buffer.Sort((x, y) => x.Occurrence.CompareTo(y.Occurrence));
        }
        public void TimeOrderDsc()
        {
            Buffer.Sort((x, y) => y.Occurrence.CompareTo(x.Occurrence));
        }
        public List<LogContent> FilterByLoglevel(LogLevel loglevel)
        {
            return Buffer.FindAll(log => log.Level == loglevel);
        }
    }

    public struct logstatics
    {
        public string item;
        public string value;
        public long Timestamp;

        // 将 UNIX 时间戳转换为 DateTime
        //DateTime dateTime = DateTimeOffset.FromUnixTimeSeconds(Timestamp).DateTime;
        public DateTime FromUnixTime()
        {
            return DateTimeOffset.FromUnixTimeSeconds(Timestamp).DateTime;
        }

    }


    public class TotalAccessSattistic
    {
        private ulong totalAccess;
        /// <summary>
        /// 总访问量
        /// </summary>
        public ulong TotalAccess
        {
            get
            {
                return this.totalAccess;
            }
        }
        private void Reset()
        { this.totalAccess = 0; }
        public void StasticAccess(List<LogContent> buf, string flagstr = "HandleClientComm")
        {
            foreach (var cnt in buf)
            {
                if (cnt.Message == flagstr)
                    this.totalAccess++;
            }
        }
    }

    //将日志写成文本文件,注意在多线程环境下要排除线程互斥。
    public class NtLog
    {
        //private Queue<LogBuffer> Buff = new Queue<LogBuffer>();
        private Queue<LogContent> buffer = new Queue<LogContent>();
        public string LogPath { get; }
        private string curfilepath = string.Empty;
        private string errorLgFile = string.Empty;  //定义从Exception到Fault这5个层级为Error
        private Task task;  //不要删除,多线程写日志时会用到
        private Stopwatch watcher = new Stopwatch();
        private long maxms, minms, lastms;
        private volatile bool IsWriting = false;
        public bool Writing { get { return IsWriting; } }
        /// <summary>
        /// 平均耗时
        /// </summary>
        public long AverageConsum
        {
            get
            {
                return (maxms + minms + lastms) / 3;
            }
        }
        public NtLog()
        {
            this.LogPath = AppDomain.CurrentDomain.BaseDirectory;


            创建日志文件夹
            this.LogPath = CreateLogDirectory();
            MakeLogFileName();
            maxms = minms = lastms = 0;
        }
        public void Enqueue(LogContent log)
        {
            this.buffer.Enqueue(log);
        }
        public void Enqueue(List<LogContent> logs)
        {
            foreach (LogContent log in logs)
            {
                this.buffer.Enqueue(log);
            }
        }
        public void Enqueue(LogBuffer logbuf)
        {
            foreach (LogContent log in logbuf.Buffer)
            {
                this.buffer.Enqueue(log);
            }
        }
        public void OnLogging(List<LogContent> logs)
        {
            //#if DEBUG
            //            TempLog.logging($"查看原始数据。{logs.Count} ");//{logs.First().Message}
            //#endif
            //this.Buff.Enqueue(new LogBuffer(logs));
            this.Enqueue(logs);

            this.UpdatePathFileName();
            if (this.IsWriting == false && this.buffer.Count > 0)
            {
                //LogBuffer Temp = this.Buff.Dequeue();
                //while (this.Buff.Count > 0)
                //{
                //    Temp.Insert(this.Buff.Dequeue());
                //}
                WriteLogByThreadV4(this.buffer);
            }

        }
        public void OnLogging(Queue<LogContent> logs)
        {
            for (int i = 0; i < logs.Count; i++)
            {
                this.buffer.Enqueue(logs.Dequeue());
            }

            this.UpdatePathFileName();
            if (this.IsWriting == false && this.buffer.Count > 0)
            {
                //LogBuffer Temp = this.Buff.Dequeue();
                //while (this.Buff.Count > 0)
                //{
                //    Temp.Insert(this.Buff.Dequeue());
                //}
                WriteLogByThreadV4(this.buffer);
            }
        }
        public static string CreateLogDirectory()
        {
            string path = AppDomain.CurrentDomain.BaseDirectory;

            // 获取当前应用程序域的名称(通常是程序集名称)
            string assemblyName = AppDomain.CurrentDomain.FriendlyName;

            // 去掉路径和扩展名,只保留文件名
            assemblyName = Path.GetFileNameWithoutExtension(assemblyName);

            // 组合成完整的路径
            path = System.IO.Path.Combine(path, assemblyName + "Log");
            //TempLog.logging(path);
            //创建日志文件夹
            Directory.CreateDirectory(path);
            return path;
        }
        public void UpdatePathFileName()
        {
            string path = AppDomain.CurrentDomain.BaseDirectory;

            // 获取当前应用程序域的名称(通常是程序集名称)
            string assemblyName = AppDomain.CurrentDomain.FriendlyName;

            // 去掉路径和扩展名,只保留文件名
            assemblyName = Path.GetFileNameWithoutExtension(assemblyName);

            // 组合成完整的路径
            path = System.IO.Path.Combine(path, assemblyName + "Log");
            //TempLog.logging(path);
            //创建日志文件夹
            Directory.CreateDirectory(path);

            string dn = DateTime.Now.ToString("yyyy-MM-dd");

            this.curfilepath = Path.Combine(this.LogPath, assemblyName + dn + ".log");
            this.errorLgFile = Path.Combine(this.LogPath, assemblyName + dn + "err.log");
        }
        public void MakeLogFileName()
        {
            // 获取当前应用程序域的名称(通常是程序集名称)
            string assemblyName = AppDomain.CurrentDomain.FriendlyName;

            // 去掉路径和扩展名,只保留文件名
            assemblyName = Path.GetFileNameWithoutExtension(assemblyName);

            string dn = DateTime.Now.ToString("yyyy-MM-dd");

            this.curfilepath = Path.Combine(this.LogPath, assemblyName + dn + ".log");
            this.errorLgFile = Path.Combine(this.LogPath, assemblyName + dn + "err.log");
        }

        public void WriteLogFile()
        {
            using (StreamWriter writer = new StreamWriter(this.curfilepath, true)) // true表示追加模式  
            {
                foreach (var cnt in this.buffer)
                {
                    writer.WriteLine(cnt.ToString());
                }
            }
        }
        public void WriteErrorLog()
        {
            using (StreamWriter writer = new StreamWriter(this.errorLgFile, true)) // true表示追加模式  
            {
                foreach (var cnt in this.buffer)
                {
                    if (cnt.Level >= LogLevel.Warning)
                        writer.WriteLine(LogContentX.TraceDetail(cnt));
                }

            }
        }

        //发现它仍然阻塞主线程
        //注意只有一个线程写,不能多个线程同时写文件。
        //请注意,Buffer.Remove(cnt) 在循环中可能会导致问题,因为从集合中移除元素会改变集合的大小,从而可能导致迭代器失效。为了避免这个问题,可以先收集需要删除的元素,然后在循环结束后统一删除它们。
        public void WriteLogByThread(LogBuffer logs)
        {
            this.watcher.Start();
            this.IsWriting = true;
            //#if DEBUG
            //            TempLog.logging($"BeofreWriteLog。{this.curfilepath} {this.errorLgFile}");
            //#endif
            //this.WriteLogFile
            // 使用Task.Run在后台线程中执行文件写入操作
            this.task = Task.Run(() =>
            {
                //FileStream可以设置成独享锁定模式,防止 线程互斥
                using (FileStream fs1 = new FileStream(this.curfilepath, FileMode.Append, FileAccess.Write, FileShare.None),
                        fs2 = new FileStream(this.errorLgFile, FileMode.Append, FileAccess.Write, FileShare.None))
                {
                    using (StreamWriter writer = new StreamWriter(fs1), writer2 = new StreamWriter(fs2))
                    {
                        foreach (var cnt in logs.Buffer)
                        {
                            writer.WriteLine(cnt.ToString());

                            if (cnt.Level >= LogLevel.Warning)
                                writer2.WriteLine(LogContentX.TraceDetail(cnt));
                        }
                    }
                }
                //Buffer没有上锁是希望它尽快完成操作,但有风险
            });
            this.watcher.Stop();
            this.IsWriting = false;
            if (this.lastms > 0 && this.lastms > this.maxms)
            {
                this.maxms = this.lastms;
            }
            if (this.lastms > 0 && this.minms == 0)
                this.minms = this.lastms;
            if (this.lastms > 0 && this.lastms < this.minms)
            {
                this.minms = this.lastms;
            }
            this.lastms = watcher.ElapsedMilliseconds;
        }

        //如果没有errlog就不写
        public void WriteLogByThreadV2(LogBuffer logs)
        {
            this.watcher.Start();
            this.IsWriting = true;
            Queue<LogContent> errlogs = new Queue<LogContent>();
            //#if DEBUG
            //            TempLog.logging($"BeofreWriteLog。{this.curfilepath} {this.errorLgFile}");
            //#endif
            //this.WriteLogFile
            // 使用Task.Run在后台线程中执行文件写入操作
            this.task = Task.Run(() =>
            {
                //FileStream可以设置成独享锁定模式,防止 线程互斥
                using (FileStream fs1 = new FileStream(this.curfilepath, FileMode.Append, FileAccess.Write, FileShare.None))
                {
                    using (StreamWriter writer = new StreamWriter(fs1))
                    {
                        foreach (var cnt in logs.Buffer)
                        {
                            writer.WriteLine(cnt.ToString());

                            if (cnt.Level >= LogLevel.Warning)
                                errlogs.Enqueue(cnt);
                        }
                    }
                }
                if (errlogs.Count > 0)
                {
                    using (FileStream fs2 = new FileStream(this.errorLgFile, FileMode.Append, FileAccess.Write, FileShare.None))
                    {
                        using (StreamWriter writer2 = new StreamWriter(fs2))
                        {
                            for (int i = 0; i < errlogs.Count; i++)
                            {
                                writer2.WriteLine(errlogs.Dequeue().ToString());
                            }
                        }
                    }
                }
                //Buffer没有上锁是希望它尽快完成操作,但有风险
            });
            this.watcher.Stop();
            this.IsWriting = false;
            if (this.lastms > 0 && this.lastms > this.maxms)
            {
                this.maxms = this.lastms;
            }
            if (this.lastms > 0 && this.minms == 0)
                this.minms = this.lastms;
            if (this.lastms > 0 && this.lastms < this.minms)
            {
                this.minms = this.lastms;
            }
            this.lastms = watcher.ElapsedMilliseconds;
        }
        public void WriteLogByThreadV3(Queue<LogContent> queue)
        {
            this.watcher.Start();
            this.IsWriting = true;
            Queue<LogContent> errlogs = new Queue<LogContent>();
            //#if DEBUG
            //            TempLog.logging($"BeofreWriteLog。{this.curfilepath} {this.errorLgFile}");
            //#endif
            //this.WriteLogFile
            // 使用Task.Run在后台线程中执行文件写入操作
            this.task = Task.Run(() =>
            {
                //FileStream可以设置成独享锁定模式,防止 线程互斥
                using (FileStream fs1 = new FileStream(this.curfilepath, FileMode.Append, FileAccess.Write, FileShare.None))
                {
                    using (StreamWriter writer = new StreamWriter(fs1))
                    {
                        //foreach (var cnt in queue)
                        //{
                        //    writer.WriteLine(cnt.ToString());
                        //    ;
                        //    if (cnt.Level >= LogLevel.Warning)
                        //        errlogs.Enqueue(cnt);
                        //}
                        while (queue.Count > 0)
                        {
                            var tmp = queue.Dequeue();
                            writer.WriteLine(tmp.ToString());
                            if (tmp.Level >= LogLevel.Warning)
                                errlogs.Enqueue(tmp);
                        }
                    }
                }
                if (errlogs.Count > 0)
                {
                    using (FileStream fs2 = new FileStream(this.errorLgFile, FileMode.Append, FileAccess.Write, FileShare.None))
                    {
                        using (StreamWriter writer2 = new StreamWriter(fs2))
                        {
                            for (int i = 0; i < errlogs.Count; i++)
                            {
                                writer2.WriteLine(errlogs.Dequeue().ToString());
                            }
                        }
                    }
                }
                //Buffer没有上锁是希望它尽快完成操作,但有风险
            });
            this.watcher.Stop();
            this.IsWriting = false;
            if (this.lastms > 0 && this.lastms > this.maxms)
            {
                this.maxms = this.lastms;
            }
            if (this.lastms > 0 && this.minms == 0)
                this.minms = this.lastms;
            if (this.lastms > 0 && this.lastms < this.minms)
            {
                this.minms = this.lastms;
            }
            this.lastms = watcher.ElapsedMilliseconds;
        }
        public void WriteLogByThreadV4(Queue<LogContent> queue)
        {
            this.watcher.Start();
            this.IsWriting = true;
            Queue<LogContent> errlogs = new Queue<LogContent>();
            //#if DEBUG
            //            TempLog.logging($"BeofreWriteLog。{this.curfilepath} {this.errorLgFile}");
            //#endif
            //this.WriteLogFile
            // 使用Task.Run在后台线程中执行文件写入操作
            this.task = Task.Run(() =>
            {
                //FileStream可以设置成独享锁定模式,防止 线程互斥
                using (FileStream fs1 = new FileStream(this.curfilepath, FileMode.Append, FileAccess.Write, FileShare.None))
                {
                    using (StreamWriter writer = new StreamWriter(fs1))
                    {
                        //foreach (var cnt in queue)
                        //{
                        //    writer.WriteLine(cnt.ToString());
                        //    ;
                        //    if (cnt.Level >= LogLevel.Warning)
                        //        errlogs.Enqueue(cnt);
                        //}
                        while (queue.Count > 0)
                        {
                            var tmp = queue.Dequeue();
                            writer.WriteLine(tmp.ToString());
                            if (tmp.Level >= LogLevel.Warning)
                                errlogs.Enqueue(tmp);
                        }
                    }
                }
                if (errlogs.Count > 0)
                {
                    using (FileStream fs2 = new FileStream(this.errorLgFile, FileMode.Append, FileAccess.Write, FileShare.None))
                    {
                        using (StreamWriter writer2 = new StreamWriter(fs2))
                        {
                            for (int i = 0; i < errlogs.Count; i++)
                            {
                                writer2.WriteLine(LogContentX.TraceDetail(errlogs.Dequeue()));
                            }
                        }
                    }
                }
                //Buffer没有上锁是希望它尽快完成操作,但有风险
            });
            this.watcher.Stop();
            this.IsWriting = false;
            if (this.lastms > 0 && this.lastms > this.maxms)
            {
                this.maxms = this.lastms;
            }
            if (this.lastms > 0 && this.minms == 0)
                this.minms = this.lastms;
            if (this.lastms > 0 && this.lastms < this.minms)
            {
                this.minms = this.lastms;
            }
            this.lastms = watcher.ElapsedMilliseconds;
        }
    }
}
相关推荐
浮生如梦_32 分钟前
C#Halcon窗体鼠标交互生成菜单
图像处理·计算机视觉·c#·视觉检测·交互
军训猫猫头7 小时前
68.浏览文件并选择文件 C#例子 WPF例子
开发语言·c#·wpf
幻想趾于现实8 小时前
在C#中,Array,List,ArrayList,Dictionary,Hashtable,SortList,Stack的区别
开发语言·c#·list
xiaowu0809 小时前
深入理解C#结构型设计模式:类适配器与对象适配器
算法·设计模式·c#
pchmi10 小时前
C# OpenCV机器视觉:多尺度细节提升
人工智能·opencv·c#·机器视觉·opencvsharp
2401_8906658611 小时前
(免费送源码)计算机毕业设计原创定制:C#+Asp.Net+SQL Server C#(asp.net)大学生创新创业项目管理系统
java·spring boot·mysql·小程序·c#·asp.net·课程设计
程序leo源13 小时前
数据结构:算法复杂度
android·c语言·开发语言·数据结构·c++·算法·c#
Rotion_深13 小时前
基于 .NET 8.0 gRPC通讯架构设计讲解,客户端+服务端
c#·grpc
幻想趾于现实15 小时前
C# Winform怎么设计串口,客户端和相机控件界面显示
数码相机·c#
玖石书17 小时前
【C#】任务调度的实现原理与组件应用Quartz.Net
开发语言·c#·.net