运用C#编写Http服务器
什么是HTTP服务器
Web服务器是指驻留于因特网上某种类型计算机的程序。当Web浏览器(客户端)连到服务器上并请求文件时,服务器将处理该请求并将文件反馈到该浏览器上,附带的信息会告诉浏览器如何查看该文件(即文件类型)。服务器使用HTTP(超文本传输协议)与客户机浏览器进行信息交流,这就是人们常把它们称为HTTP服务器的原因。
HTTP协议
HTTP是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展。目前在WWW中使用的是HTTP/1.0的第六版,HTTP/1.1的规范化工作正在进行之中,而且HTTP-NG(Next Generation of HTTP)的建议已经提出。
关于HTTP协议讲解这里有一篇文章,感兴趣可以去看看 https://blog.csdn.net/gueter/article/details/1524447
代码
BaseHeader类
用于定义一些HTTP请求类和HTTP响应类的公共字段
public class BaseHeader
{
/// <summary>
/// http编码格式
/// </summary>
public Encoding Encoding { get; set; }
/// <summary>
/// 报文类型
/// </summary>
public string Content_Type { get; set; }
/// <summary>
/// 报文长度
/// </summary>
public int Content_Length { get; set; }
/// <summary>
/// 报头的编码格式字段
/// </summary>
public string Content_Encoding { get; set; }
/// <summary>
/// 报文Body
/// </summary>
public string Content { get; set; }
/// <summary>
/// 用于存储报头的字典
/// </summary>
public Dictionary<string, string> Headers { get; set; }
/// <summary>
/// 日志单例对象
/// </summary>
public static LogManager _logger = LogManager.Instance;
}
HttpServer类
用于监听端口开启服务
public class HttpServer
{
/// <summary>
/// 服务器IP
/// </summary>
public string ServerIP { get; private set; } /// <summary>
/// 服务器端口
/// </summary>
public int ServerPort { get; private set; } /// <summary>
/// 是否运行
/// </summary>
public bool IsRunning { get; private set; } /// <summary>
/// 服务端Socket
/// </summary>
private TcpListener serverListener; /// <summary>
/// 日志单例对象
/// </summary>
public static LogManager _logger = LogManager.Instance; public event Action<HttpRequest, HttpResponse> PostOps;//post事件
public event Action<HttpRequest, HttpResponse> GetOps;//get事件 /// <summary>
/// 构造函数
/// </summary>
/// <param name="ip">IP地址</param>
/// <param name="port">端口</param>
public HttpServer(int port)
{
this.ServerPort = port;
}
public HttpServer(string port)
{
this.ServerPort = Convert.ToInt32(port);
}
//开启服务器
public void Start()
{
if (IsRunning) return;
//创建服务端Socket
this.serverListener = new TcpListener(IPAddress.Any, ServerPort);
this.IsRunning = true;
this.serverListener.Start();
_logger.Info(string.Format("Http服务器正在监听{0}", serverListener.LocalEndpoint.ToString()));
try
{
while (IsRunning)
{
TcpClient client = serverListener.AcceptTcpClient();
Thread requestThread = new Thread(() => { ProcessRequest(client); });
requestThread.IsBackground = true;
requestThread.Start();
}
}
catch
{ }
}
//关闭服务器
public void Stop()
{
if (!IsRunning) return;
IsRunning = false;
serverListener.Stop();
} #region 内部方法
/// <summary>
/// 处理客户端请求
/// </summary>
/// <param name="tcpClient">客户端Socket</param>
private void ProcessRequest(TcpClient tcpClient)
{
//处理请求
Stream clientStream = tcpClient.GetStream();
Thread.Sleep(390);//不知道为什么不Sleep一下接收不到body,可以试试去掉
if (clientStream != null)
{
//构造HTTP请求
HttpRequest request = new HttpRequest(clientStream); //构造HTTP响应
HttpResponse response = new HttpResponse(clientStream); //处理请求类型
switch (request.Method)//根据请求方法触发不同事件
{
case "GET":
OnGet(request, response);
break;
case "POST":
OnPost(request, response);
break;
default:
OnDefault(request, response);
break;
}
} }
#endregion #region 方法
/// <summary>
/// 响应Get请求
/// </summary>
/// <param name="request">请求报文</param>
public void OnGet(HttpRequest request, HttpResponse response)
{
GetOps(request, response);
} /// <summary>
/// 响应Post请求
/// </summary>
/// <param name="request"></param>
public void OnPost(HttpRequest request, HttpResponse response)
{
PostOps(request, response);
} /// <summary>
/// 响应默认请求
/// </summary>
public void OnDefault(HttpRequest request, HttpResponse response)
{ }
#endregion
}
HttpRequest类
用于接收HTTP请求,并解析
public class HttpRequest : BaseHeader
{
#region 字段属性
/// <summary>
/// URL参数
/// </summary>
public Dictionary<string, string> Params { get; private set; }
/// <summary>
/// http请求方法
/// </summary>
public string Method { get; set; }
/// <summary>
/// http请求的URL地址
/// </summary>
public string URL { get; set; }
/// <summary>
/// http协议版本
/// </summary>
public string HTTP_Version { get; set; }
#endregion /// <summary>
/// 定义缓冲区
/// </summary>
private const int MAX_SIZE = 1024 * 1024 * 2;
private byte[] bytes = new byte[MAX_SIZE];
private Stream DataStream; public HttpRequest(Stream stream)
{
this.DataStream = stream;
string dataString = GetData(DataStream); var dataArray = Regex.Split(dataString, Environment.NewLine);
var requestLine = Regex.Split(dataArray[0], @"(\s+)")
.Where(e => e.Trim() != string.Empty)
.ToArray();//分割出请求行的信息
if (requestLine.Length > 0) this.Method = requestLine[0];
if (requestLine.Length > 1) this.URL = Uri.UnescapeDataString(requestLine[1]);
if (requestLine.Length > 2) this.HTTP_Version = requestLine[2]; this.Headers = GetHeader(dataArray,out int index); if (this.Method == "POST")
{
this.Content_Length = Convert.ToInt32(Headers["Content-Length"]);
if (Content_Length != 0)//数据长度不等于0
{
this.Content_Type = Headers["Content-Type"];
this.Encoding = Content_Type.Split('=')[1] == "utf-8" ? Encoding.UTF8 : Encoding.Default;
this.Content = GetBody(dataArray, index);//真正的数据
_logger.Info("收到消息:\r\n" + Content + "\r\n");
//Task.Run(() =>
//{
//if (socket != null)
//{
//byte[] buffer = this.Encoding.GetBytes(this.Content);
//socket.Send(buffer);
//}
//else
//{
// _logger.Debug("上位机未连接!");
//}
//});
}
else
{
_logger.Info("报文为空!");
}
}
} /// <summary>
/// 获取数据流中的数据data
/// </summary>
/// <param name="DataStream"></param>
/// <returns></returns>
public string GetData(Stream DataStream)
{
try
{
var length = 0;
var data = string.Empty;
do
{
length = DataStream.Read(bytes, 0, MAX_SIZE - 1);
data += Encoding.UTF8.GetString(bytes, 0, length);
}
while (length > 0 && !data.Contains("\r\n\r\n"));
return data;
}
catch
{
return "";
}
} /// <summary>
/// 获取报头header
/// </summary>
/// <param name="dataArray"></param>
/// <returns></returns>
public Dictionary<string,string> GetHeader(string[] dataArray,out int index)
{
var header = new Dictionary<string, string>();
index = 0;
foreach (var item in dataArray)
{
index++;
if (item == "")//读取到空行表示header已经读取完成
{
return header;
}
if (item.Contains(':'))
{
var dataTemp = item.Split(':').ToList();//把报头数据分割以键值对方式存入字典
if (dataTemp.Count > 2)//特殊情况Host有两个“:”
{
for (int i = 2; i < dataTemp.Count;)
{
dataTemp[1] += ":"+dataTemp[i];
dataTemp.Remove(dataTemp[i]);
}
}
header.Add(dataTemp[0].Trim(), dataTemp[1].Trim());
}
}
return header;
} /// <summary>
/// 获取报文body
/// </summary>
/// <param name="dataArray"></param>
/// <param name="index"></param>
/// <returns></returns>
public string GetBody(string[] dataArray, int index)
{
string Body = string.Empty;
for (int i = index ; i < dataArray.Length; i++)
{
Body += dataArray[i];
}
return Body;
} #region 反射
//通过反射查找请求对应的方法(未完成)
public void reflex()
{
Type t1 = this.GetType();
//根据字符标题,取得当前函数调用
MethodInfo method = t1.GetMethod("miaox");
//获取需要传入的参数 ParameterInfo[] parms = method.GetParameters();
int haha = 1111;
//调用
method.Invoke(this, new object[] { haha });
} public void miao(int x)
{ }
#endregion
}
HttpResponse类
用于构造响应HTTP请求
public class HttpResponse : BaseHeader
{
#region 字段属性
/// <summary>
/// http协议版本
/// </summary>
public string HTTP_Version { get; set; }
/// <summary>
/// 状态码
/// </summary>
public string StatusCode { get; set; }
/// <summary>
/// http数据流
/// </summary>
private Stream DataStream;
#endregion
public HttpResponse(Stream stream)
{
this.DataStream = stream;
} /// <summary>
/// 构建响应头部
/// </summary>
/// <returns></returns>
protected string BuildHeader()
{
StringBuilder builder = new StringBuilder();//StringBuilder(字符串变量)进行运算时,是一直在已有对象操作的,适合大量频繁字符串的拼接或删除
//string(字符串常量)在进行运算的时候是重新生成了一个新的string对象,不适合大量频繁字符串的拼接或删除 if (!string.IsNullOrEmpty(StatusCode))
builder.Append(HTTP_Version + " " + StatusCode + "\r\n"); if (!string.IsNullOrEmpty(this.Content_Type))
builder.AppendLine("Content-Type:" + this.Content_Type);
return builder.ToString();
} /// <summary>
/// 发送数据
/// </summary>
public void Send()
{
if (!DataStream.CanWrite) return;
try
{
//发送响应头
var header = BuildHeader();
byte[] headerBytes = this.Encoding.GetBytes(header);
DataStream.Write(headerBytes, 0, headerBytes.Length); //发送空行
byte[] lineBytes = this.Encoding.GetBytes(System.Environment.NewLine);
DataStream.Write(lineBytes, 0, lineBytes.Length); //发送内容
byte[] buffer = this.Encoding.GetBytes(this.Content);
DataStream.Write(buffer, 0, buffer.Length);
}
catch(Exception e)
{
_logger.Debug("服务器响应异常!" + e.Message);
}
finally
{
DataStream.Close();
}
}
}
调用
#region...日志...
/// <summary>
/// 日志单例对象
/// </summary>
public static LogManager _logger = LogManager.Instance;
/// <summary>
/// 写入日志框
/// </summary>
/// <param name="obj">日志对象</param>
private void LogManager_Event(LogInfo obj)
{
log_txt.Font = new Font("黑体", 8, FontStyle.Regular);
//若是超过N行 则清除
if (log_txt.Lines.Length > 500)
{
log_txt.Clear();
log_txt.AppendText("更多日志,请到日志文件中查看。\r\n");
}
if (obj.LogLevel == LogLevel.Info)
{
log_txt.SelectionColor = Color.DarkBlue;
}
if (obj.LogLevel == LogLevel.Error)
{
log_txt.SelectionColor = Color.Red;
}
if (obj.LogLevel == LogLevel.Debug)
{
log_txt.SelectionColor = Color.Orange;
}
if (obj.LogLevel == LogLevel.Fatal)
{
//this._textBox.SelectionColor = Color.Red;
log_txt.SelectionColor = Color.Purple;
}
log_txt.AppendText(obj.Message + "\r\n");
log_txt.ScrollToCaret();
}
/// <summary>
/// 初始化日志
/// </summary>
private void LogInit()
{
LogManager.Event += LogManager_Event;
}
#endregion
private void Form1_Load(object sender, EventArgs e)
{
HttpPort_txt.Text = MsgList[0];
LogInit();
_logger.Info("日志初始化...\r\n");
Control.CheckForIllegalCrossThreadCalls = false;
httpServer = new HttpServer(HttpPort_txt.Text);
httpServer.GetOps += HttpServer_GetOps;
httpServer.PostOps += HttpServer_PostOps;
Task.Run(new Action(() => { httpServer.Start(); }));
_logger.Info("服务器正在开启,请稍等...");
}
日志类LogManager
用于显示日志信息和生成日志文件
/// <summary>
/// 日志级别
/// </summary>
public enum LogLevel
{
/// <summary>
/// 信息级别
/// </summary>
Info, /// <summary>
/// debug级别
/// </summary>
Debug, /// <summary>
/// 错误级别
/// </summary>
Error, /// <summary>
/// 致命级别
/// </summary>
Fatal
} /// <summary>
/// 日志信息
/// </summary>
public class LogInfo
{
/// <summary>
/// 时间
/// </summary>
public DateTime Time { get; set; } /// <summary>
/// 线程id
/// </summary>
public int ThreadId { get; set; } /// <summary>
/// 日志级别
/// </summary>
public LogLevel LogLevel { get; set; } /// <summary>
/// 异常源
/// </summary>
public string Source { get; set; } /// <summary>
/// 异常信息
/// </summary>
public string Message { get; set; } /// <summary>
/// 异常对象
/// </summary>
public Exception Exception { get; set; } /// <summary>
/// 日志类型
/// </summary>
public string ExceptionType { get; set; } /// <summary>
/// 请求路径
/// </summary>
public string RequestUrl { get; set; } /// <summary>
/// 客户端代理
/// </summary>
public string UserAgent { get; set; }
} /// <summary>
/// 日志组件
/// </summary>
public class LogManager
{
/// <summary>
/// 日志对象单例
/// </summary>
static volatile LogManager _instance;
static object _lock = new object();//双重验证锁 /// <summary>
/// 获取日志对象的单例
/// </summary>
public static LogManager Instance
{
get
{
if (_instance == null)
{
lock (_lock)
{
if (_instance == null)
{
_instance = new LogManager();
}
}
}
return _instance;
}
} static ConcurrentQueue<Tuple<string, string>> LogQueue = new ConcurrentQueue<Tuple<string, string>>(); /// <summary>
/// 自定义事件
/// </summary>
public static event Action<LogInfo> Event; static DateTime _now
{
get { return DateTime.Now; }
}//日志记录时间 private LogManager()
{
var writeTask = new Task((obj) =>
{
while (true)
{
Pause.WaitOne(1000, true);
List<string[]> temp = new List<string[]>();
Tuple<string, string> logItem;
LogQueue.TryDequeue(out logItem);
if (logItem != null)
{
string logPath = logItem.Item1;
string logMergeContent = string.Concat(logItem.Item2, "----------------------------------------------------------------------------------------------------------------------\r\n");
string[] logArr = temp.FirstOrDefault(d => d[0].Equals(logPath));
if (logArr != null)
{
logArr[1] = string.Concat(logArr[1], logMergeContent);
}
else
{
logArr = new[]
{
logPath,
logMergeContent
};
temp.Add(logArr); foreach (var item in temp)
{
WriteText(item[0], item[1]);
}
}
} }
}, null, TaskCreationOptions.LongRunning); writeTask.Start();
} private static AutoResetEvent Pause => new AutoResetEvent(false); /// <summary>
/// 日志存放目录,默认日志放在当前应用程序运行目录下的logs文件夹中
/// </summary>
public static string LogDirectory
{
get { return Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory).Any(s => s.Contains("Web.config")) ? AppDomain.CurrentDomain.BaseDirectory + @"App_Data\Logs\" : Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs"); }
set
{
}
} /// <summary>
/// 写入Info级别的日志
/// </summary>
/// <param name="info"></param>
public void Info(string info)
{ LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"时间:{_now}\r\n线程ID:[{Thread.CurrentThread.ManagedThreadId}]\r\n日志级别:{nameof(info).ToUpper()}\r\n日志消息:{info}\r\n"));
var log = new LogInfo()
{
LogLevel = LogLevel.Info,
Message = info,
Time = _now,
ThreadId = Thread.CurrentThread.ManagedThreadId
};
Event?.Invoke(log);
} /// <summary>
/// 写入Info级别的日志
/// </summary>
/// <param name="source"></param>
/// <param name="info"></param>
public void Info(string source, string info)
{
LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"时间:{_now}\r\n线程ID:[{Thread.CurrentThread.ManagedThreadId}]\r\n日志级别:{nameof(info).ToUpper()}\r\n日志资源:{source}\r\n日志消息:{info}\r\n"));
LogInfo log = new LogInfo()
{
LogLevel = LogLevel.Info,
Message = info,
Time = _now,
ThreadId = Thread.CurrentThread.ManagedThreadId,
Source = source
};
Event?.Invoke(log);
} /// <summary>
/// 写入Info级别的日志
/// </summary>
/// <param name="source"></param>
/// <param name="info"></param>
public void Info(Type source, string info)
{
LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"时间:{_now}\r\n线程ID:[{Thread.CurrentThread.ManagedThreadId}]\r\n日志级别:{nameof(info).ToUpper()}\r\n日志资源名:{source.FullName}\r\n日志消息:{info}\r\n"));
LogInfo log = new LogInfo()
{
LogLevel = LogLevel.Info,
Message = info,
Time = _now,
ThreadId = Thread.CurrentThread.ManagedThreadId,
Source = source.FullName
};
Event?.Invoke(log);
} /// <summary>
/// 写入debug级别日志
/// </summary>
/// <param name="debug">异常对象</param>
public void Debug(string debug)
{
LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"时间:{_now}\r\n线程ID:[{Thread.CurrentThread.ManagedThreadId}]\r\n日志级别:{nameof(debug).ToUpper()}\r\n日志消息:{debug}\r\n"));
LogInfo log = new LogInfo()
{
LogLevel = LogLevel.Debug,
Message = debug,
Time = _now,
ThreadId = Thread.CurrentThread.ManagedThreadId
};
Event?.Invoke(log);
} /// <summary>
/// 写入debug级别日志
/// </summary>
/// <param name="source">异常源的类型</param>
/// <param name="debug">异常对象</param>
public void Debug(string source, string debug)
{
LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"时间:{_now}\r\n线程ID:[{Thread.CurrentThread.ManagedThreadId}]\r\n日志级别:{nameof(debug).ToUpper()}\r\n日志资源:{source}\r\n日志消息:{debug}\r\n"));
LogInfo log = new LogInfo()
{
LogLevel = LogLevel.Debug,
Message = debug,
Time = _now,
ThreadId = Thread.CurrentThread.ManagedThreadId,
Source = source
};
Event?.Invoke(log);
} /// <summary>
/// 写入debug级别日志
/// </summary>
/// <param name="source">异常源的类型</param>
/// <param name="debug">异常对象</param>
public void Debug(Type source, string debug)
{
LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"时间:{_now}\r\n线程ID:[{Thread.CurrentThread.ManagedThreadId}]\r\n日志级别:{nameof(debug).ToUpper()}\r\n日志资源:{source.FullName}\r\n日志消息:{debug}\r\n"));
LogInfo log = new LogInfo()
{
LogLevel = LogLevel.Debug,
Message = debug,
Time = _now,
ThreadId = Thread.CurrentThread.ManagedThreadId,
Source = source.FullName
};
Event?.Invoke(log);
} /// <summary>
/// 写入error级别日志
/// </summary>
/// <param name="error">异常对象</param>
public void Error(Exception error)
{
LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"时间:{_now}\r\n线程ID:[{Thread.CurrentThread.ManagedThreadId}]\r\n日志级别:{nameof(error).ToUpper()}\r\n日志资源:{error.Source}\r\n日志消息:{error.Message}\r\n"));
LogInfo log = new LogInfo()
{
LogLevel = LogLevel.Error,
Message = error.Message,
Time = _now,
ThreadId = Thread.CurrentThread.ManagedThreadId,
Source = error.Source,
Exception = error,
ExceptionType = error.GetType().Name
};
Event?.Invoke(log);
} public void Error(string error)
{
LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"时间:{_now}\r\n线程ID:[{Thread.CurrentThread.ManagedThreadId}]\r\n日志级别:{nameof(error).ToUpper()}\r\n日志消息:{error}\r\n"));
var log = new LogInfo()
{
LogLevel = LogLevel.Error,
Message = error,
Time = _now,
ThreadId = Thread.CurrentThread.ManagedThreadId
};
Event?.Invoke(log);
} /// <summary>
/// 写入error级别日志
/// </summary>
/// <param name="source">异常源的类型</param>
/// <param name="error">异常对象</param>
public void Error(Type source, Exception error)
{
LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"时间:{_now}\r\n线程ID:[{Thread.CurrentThread.ManagedThreadId}]\r\n日志级别:{nameof(error).ToUpper()}\r\n日志资源:{source.FullName}\r\n日志消息:{error.Message}\r\n"));
LogInfo log = new LogInfo()
{
LogLevel = LogLevel.Error,
Message = error.Message,
Time = _now,
ThreadId = Thread.CurrentThread.ManagedThreadId,
Source = source.FullName,
Exception = error,
ExceptionType = error.GetType().Name
};
Event?.Invoke(log);
} /// <summary>
/// 写入error级别日志
/// </summary>
/// <param name="source">异常源的类型</param>
/// <param name="error">异常信息</param>
public void Error(Type source, string error)
{
LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"时间:{_now}\r\n线程ID:[{Thread.CurrentThread.ManagedThreadId}]\r\n日志级别:{nameof(error).ToUpper()}\r\n日志资源:{source.FullName}\r\n日志消息:{error}\r\n"));
LogInfo log = new LogInfo()
{
LogLevel = LogLevel.Error,
Message = error,
Time = _now,
ThreadId = Thread.CurrentThread.ManagedThreadId,
Source = source.FullName,
//Exception = error,
ExceptionType = error.GetType().Name
};
Event?.Invoke(log);
} /// <summary>
/// 写入error级别日志
/// </summary>
/// <param name="source">异常源的类型</param>
/// <param name="error">异常对象</param>
public void Error(string source, Exception error)
{
LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"时间:{_now}\r\n线程ID:[{Thread.CurrentThread.ManagedThreadId}]\r\n日志级别:{nameof(error).ToUpper()}\r\n日志资源:{source}\r\n日志消息:{error.Message}\r\n"));
LogInfo log = new LogInfo()
{
LogLevel = LogLevel.Error,
Message = error.Message,
Time = _now,
ThreadId = Thread.CurrentThread.ManagedThreadId,
Source = source,
Exception = error,
ExceptionType = error.GetType().Name
};
Event?.Invoke(log);
} /// <summary>
/// 写入error级别日志
/// </summary>
/// <param name="source">异常源的类型</param>
/// <param name="error">异常信息</param>
public void Error(string source, string error)
{
LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"时间:{_now}\r\n线程ID:[{Thread.CurrentThread.ManagedThreadId}]\r\n日志级别:{nameof(error).ToUpper()}\r\n日志资源:{source}\r\n日志消息:{error}\r\n"));
LogInfo log = new LogInfo()
{
LogLevel = LogLevel.Error,
Message = error,
Time = _now,
ThreadId = Thread.CurrentThread.ManagedThreadId,
Source = source,
//Exception = error,
ExceptionType = error.GetType().Name
};
Event?.Invoke(log);
} /// <summary>
/// 写入fatal级别日志
/// </summary>
/// <param name="fatal">异常对象</param>
public void Fatal(Exception fatal)
{
LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"时间:{_now}\r\n线程ID:[{Thread.CurrentThread.ManagedThreadId}]\r\n日志级别:{nameof(fatal).ToUpper()}\r\n日志资源:{fatal.Source}\r\n日志消息:{fatal.Message}\r\n"));
LogInfo log = new LogInfo()
{
LogLevel = LogLevel.Fatal,
Message = fatal.Message,
Time = _now,
ThreadId = Thread.CurrentThread.ManagedThreadId,
Source = fatal.Source,
Exception = fatal,
ExceptionType = fatal.GetType().Name
};
Event?.Invoke(log);
} /// <summary>
/// 写入fatal级别日志
/// </summary>
/// <param name="source">异常源的类型</param>
/// <param name="fatal">异常对象</param>
public void Fatal(Type source, Exception fatal)
{
LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"时间: {_now} \r\n线程ID:[ {Thread.CurrentThread.ManagedThreadId} ]\r\n日志级别: {nameof(fatal).ToUpper()} \r\n日志资源: {source.FullName} \r\n日志消息: {fatal.Message} \r\n"));
LogInfo log = new LogInfo()
{
LogLevel = LogLevel.Fatal,
Message = fatal.Message,
Time = _now,
ThreadId = Thread.CurrentThread.ManagedThreadId,
Source = source.FullName,
Exception = fatal,
ExceptionType = fatal.GetType().Name
};
Event?.Invoke(log);
} /// <summary>
/// 写入fatal级别日志
/// </summary>
/// <param name="source">异常源的类型</param>
/// <param name="fatal">异常对象</param>
public void Fatal(Type source, string fatal)
{
LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"时间: {_now} \r\n线程ID:[ {Thread.CurrentThread.ManagedThreadId} ]\r\n日志级别: {nameof(fatal).ToUpper()} \r\n日志资源: {source.FullName} \r\n日志消息: {fatal} \r\n"));
LogInfo log = new LogInfo()
{
LogLevel = LogLevel.Fatal,
Message = fatal,
Time = _now,
ThreadId = Thread.CurrentThread.ManagedThreadId,
Source = source.FullName,
//Exception = fatal,
ExceptionType = fatal.GetType().Name
};
Event?.Invoke(log);
} /// <summary>
/// 写入fatal级别日志
/// </summary>
/// <param name="source">异常源的类型</param>
/// <param name="fatal">异常对象</param>
public void Fatal(string source, Exception fatal)
{
LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"时间:{_now}\r\n线程ID:[{Thread.CurrentThread.ManagedThreadId}]\r\n日志级别:{nameof(fatal).ToUpper()}\r\n日志资源:{source}\r\n日志消息:{fatal.Message}\r\n"));
LogInfo log = new LogInfo()
{
LogLevel = LogLevel.Fatal,
Message = fatal.Message,
Time = _now,
ThreadId = Thread.CurrentThread.ManagedThreadId,
Source = source,
Exception = fatal,
ExceptionType = fatal.GetType().Name
};
Event?.Invoke(log);
} /// <summary>
/// 写入fatal级别日志
/// </summary>
/// <param name="source">异常源的类型</param>
/// <param name="fatal">异常对象</param>
public void Fatal(string source, string fatal)
{
LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"时间: {_now} \r\n线程ID:[ {Thread.CurrentThread.ManagedThreadId} ]\r\n日志级别: {nameof(fatal).ToUpper()} \r\n日志资源: {source} \r\n日志消息:{fatal}"));
LogInfo log = new LogInfo()
{
LogLevel = LogLevel.Fatal,
Message = fatal,
Time = _now,
ThreadId = Thread.CurrentThread.ManagedThreadId,
Source = source,
ExceptionType = fatal.GetType().Name
};
Event?.Invoke(log);
} private string GetLogPath()
{
string newFilePath;
String logDir = string.IsNullOrEmpty(LogDirectory) ? Path.Combine(Environment.CurrentDirectory, "logs") : LogDirectory;
if (!Directory.Exists(logDir))
{
Directory.CreateDirectory(logDir);
} string extension = ".log";
string fileNameNotExt = _now.ToString("yyyyMMdd");
string fileNamePattern = string.Concat(fileNameNotExt, "(*)", extension);
List<string> filePaths = Directory.GetFiles(logDir, fileNamePattern, SearchOption.TopDirectoryOnly).ToList(); if (filePaths.Count > 0)
{
int fileMaxLen = filePaths.Max(d => d.Length);
string lastFilePath = filePaths.Where(d => d.Length == fileMaxLen).OrderByDescending(d => d).FirstOrDefault();
if (new FileInfo(lastFilePath).Length > 1 * 1024 * 1024)
{
string no = new Regex(@"(?is)(?<=\()(.*)(?=\))").Match(Path.GetFileName(lastFilePath)).Value;
Int32 tempno;
bool parse = int.TryParse(no, out tempno);
string formatno = $"({(parse ? (tempno + 1) : tempno)})";
string newFileName = String.Concat(fileNameNotExt, formatno, extension);
newFilePath = Path.Combine(logDir, newFileName);
}
else
{
newFilePath = lastFilePath;
}
}
else
{
string newFileName = string.Concat(fileNameNotExt, $"({0})", extension);
newFilePath = Path.Combine(logDir, newFileName);
} return newFilePath;
} private void WriteText(string logPath, string logContent)
{
try
{
if (!File.Exists(logPath))
{
File.CreateText(logPath).Close();
} using (StreamWriter sw = File.AppendText(logPath))
{
sw.Write(logContent);
} }
catch (Exception e)
{
throw e;
}
}
}
运用C#编写Http服务器的更多相关文章
- 实战WEB 服务器(JAVA编写WEB服务器)
实战WEB 服务器(JAVA编写WEB服务器) 标签: web服务服务器javawebsockethttp服务器 2010-04-21 17:09 11631人阅读 评论(24) 收藏 举报 分类: ...
- 用 PHP 编写 http 服务器
概述 众所周知,我们一般使用 PHP 开发Web程序时需要使用到比如Apache或Nginx等Web服务器来支持,那么有没有办法直接使用PHP开发HTTP服务器,答案当然是可以的,最近看了一遍Work ...
- 【北航软件工程】Alpha阶段前端页面编写及服务器部署
前端页面编写 虽然之前对html语法有过一些了解,但是完全没有编写前端页面的经验,和我合作的czy大概也是这么个情况.在Alpha阶段的前端页面编写过程中,我们是摸着石头过河,html是个入门很快专精 ...
- Golang 编写 Tcp 服务器
Golang 作为广泛用于服务端和云计算领域的编程语言,tcp socket 是其中至关重要的功能.无论是 WEB 服务器还是各类中间件都离不开 tcp socket 的支持. Echo 服务器 拆包 ...
- 使用 acl_cpp 的 HttpServlet 类及服务器框架编写WEB服务器程序(系列文章)
在 <用C++实现类似于JAVA HttpServlet 的编程接口 > 文章中讲了如何用 HttpServlet 等相关类编写 CGI 程序,于是有网友提出了 CGI 程序低效性,不错, ...
- 深入学习用 Go 编写 HTTP 服务器
Go是一门通用的编程语言,想要学习 Go 语言的 Web 开发,就必须知道如何用 Go 启动一个 HTTP 服务器用于接收和响应来自客户端的 HTTP 请求.用 Go实现一个http server非常 ...
- php编写tcp服务器和客户端程序
这是我从别的地方看到的. 1.修改php.ini,打开extension=php_sockets.dll 2.客户端程序 SocketClient.php <?php set_time_limi ...
- JAVA编写WEB服务器
一.超文本传输协议 1.1 HTTP请求 1.2 HTTP应答 二.Socket类 三.ServerSocket类 四.Web服务器实例 4.1 HttpServer类 4.2 Requ ...
- io复用select方法编写的服务器
摘要:io多路复用是通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般都是读就绪或者写就绪),就能通知应用程序进行相应的读写操作.select函数作为io多路复用的机制,第一个参数nfds是f ...
- 01-简单编写http服务器
package com.day3; import java.io.IOException; import java.io.InputStream; import java.net.ServerSock ...
随机推荐
- 基于FLink实现的实时安全检测(一段时间内连续登录失败20次后,下一次登录成功场景)
研发背景 公司安全部目前针对内部系统的网络访问日志的安全审计,大部分都是T+1时效,每日当天,启动Python编写的定时任务,完成昨日的日志审计和检测,定时任务运行完成后,统一进行企业微信告警推送.这 ...
- 在 WXML 中使用 JS 代码
{{}} 里面可以写任何的 JS 表达式,(一定是表达式,例如定义函数等都不属于表达式).例如,下面是在 wxml 中使用 JS 表达式: <view class="price tex ...
- 华为S6720S-S24S28X-A配置参数
- soursetree 关于https:git remote: Unauthorized和username和password修改
一.sourcetree推送代码提交不上提示https:git remote: Unauthorized由于没有权限,需要登陆正确的账号以及密码即可以提交 二.SourceTree这是一个无效源路径/ ...
- ubuntu 22.04 网络配置ib网卡配置
第一步:查看Ubuntu版本与内核版本 cat /etc/issue 这说明系统的版本为:Ubuntu 20.04.4 LTS \n \l uname -a Linux gacs-gm-11 5.4. ...
- UE4笔记索引
图形 渲染 延迟渲染 三维渲染流程 渲染优化 基本渲染 材质 材质节点组合 节点分类 特别的属性 其他 坐标空间与切线空间 坐标轴 编码 平台相关 UBT编译 命令行 程序到CPU路径 C++与蓝图互 ...
- element ui中table动态列切换时,表格样式变形
现象:定义多个头部和多个数据体,可以自由切换不同的头部和相应的数据体,但是切换过程表格会变形. 解决办法:table增加索引,切换头部和数据时,修改为不同的索引,即可解决 重点:表格标签上的 key ...
- Linux(CentOS) Mysql 8.0.30 安装(多源安装)
Linux(CentOS) Mysql 8.0.30 安装(多源安装) 安装命令根据实际部署情况修改调整,CentOS一般选择通用版本Red Hat Enterprise Linux 7 本文档使用w ...
- jQuery-强大的jQuery选择器 (详解)
jq除常用的选择写法之外的更多方法记录. 原文:jQuery-强大的jQuery选择器 (详解)[转] 1. 基础选择器 Basics 名称 说明 举例 #id 根据元素Id选择 $("di ...
- GIT笔记汇总
Git的存储方式: 元空间的存储方式 SVN存储方式: 文档数据库存储类似于 K -V存储 文件版本迭代 Copy ------------------------------------------ ...