You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

205 lines
6.6 KiB

1 month ago
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Threading;
using Sog;
using SimpleHttpServer;
namespace Operation
{
internal class HttpRequestInfo
{
public HttpContext Http;
public DateTime BeginTime;
public bool StartProcess;//是否开始处理
public bool ProcessEnd; //是否处理完毕
public int ProcessResult; //错误码
}
/// 同步模式的http服务器
/// 异步模式,处理消息是多线程
/// 同步模式,处理消息是单线程,并且需要主动调用update处理
public class SyncHttpServerService
{
private object m_locker ;//锁
private HttpServer m_server;
private int m_timeoutMs;
//保存的外部的回调处理器
private Action<HttpContext> m_outCallable;
internal List<HttpRequestInfo> m_requestList = new List<HttpRequestInfo>();
List<HttpRequestInfo> m_updateRequestList = new List<HttpRequestInfo>();
public void StartHttpServer(int port, Route routeConfig, int timeout = 5000)
{
m_locker = new object();//锁
m_timeoutMs = timeout;
m_outCallable = routeConfig.Callable;
routeConfig.Callable = this.HttpRequestCallback;
List<Route> listconfig = new List<Route>();
listconfig.Add(routeConfig);
m_server = new HttpServer(port, listconfig);
Thread thread = new Thread(new ThreadStart(m_server.Listen));
thread.IsBackground = true;//设置成后台线程,如果不是后台线程,线程不是主动关闭,则会一直运行,那怕进程主线程退出也没用
thread.Start();
TraceLog.Debug("SyncHttpServerService.StartHttpServer listen on {0}", port);
}
private void HttpRequestCallback(HttpContext httpContext)
{
//停服不允许访问
if(OperationServerUtils.GetApp().IsStopping)
{
httpContext.httpResponse = new HttpResponse
{
ContentAsUTF8 = "server stop",
ReasonPhrase = "Forbidden",
StatusCode = "403"
};
return ;
}
DateTime beginTime = DateTime.Now;
bool bTimeout = false;
HttpRequestInfo info = new HttpRequestInfo();
info.Http = httpContext;
info.BeginTime = beginTime;
info.ProcessEnd = false;
lock (m_locker)
{
m_requestList.Add(info);
}
//等待处理结束
while(true)
{
if (info.ProcessEnd == true)
{
break;
}
//对于http请求来说10毫秒足够了
Thread.Sleep(10);
//判断超时
if ((DateTime.Now - beginTime).TotalMilliseconds >= m_timeoutMs)
{
TraceLog.Error("SyncHttpServerService.HttpRequestCallback request method {0} url {1} timeout!", httpContext.httpRequest.Method, httpContext.httpRequest.Url);
bTimeout = true;
break;
}
}
lock (m_locker)
{
m_requestList.Remove(info);
}
//超时
if (bTimeout)
{
httpContext.httpResponse = new HttpResponse
{
ContentAsUTF8 = "timeout",
ReasonPhrase = "InternalServerError",
StatusCode = "500"
};
}
else
{
//出错,比如处理过程异常
if(info.ProcessResult != 0)
{
httpContext.httpResponse = new HttpResponse
{
ContentAsUTF8 = "error",
ReasonPhrase = "InternalServerError",
StatusCode = "500"
};
}
//成功
else
{
httpContext.httpResponse = info.Http.httpResponse;
}
}
if (!httpContext.httpResponse.Headers.ContainsKey("Content-Type"))
{
httpContext.httpResponse.Headers["Content-Type"]="application/json; charset=utf-8";
}
HttpServer.SendResponse(httpContext);
}
//同步调用
public void Update()
{
DateTime beginTime = DateTime.Now;
//申请一个临时数组,这样可以避免循环过程中加锁
m_updateRequestList.Clear();
lock (m_locker)
{
m_updateRequestList.AddRange(m_requestList);
}
int iCount = 0;
foreach(HttpRequestInfo requestInfo in m_updateRequestList)
{
if(requestInfo.StartProcess == false)
{
requestInfo.StartProcess = true;
try
{
//HttpContext hc = new HttpContext(null);
//hc.httpRequest = requestInfo.Request;
m_outCallable(requestInfo.Http);
//不需要等待时退出
if (!requestInfo.Http.httpResponse.IsWaitFor)
{
requestInfo.ProcessEnd = true;
}
}
catch(Exception ex)
{
requestInfo.ProcessEnd = true;
requestInfo.ProcessResult = -1;
TraceLog.Exception(ex);
TraceLog.Error("SyncHttpServerService.Update request method {0} url {1} process error!"
, requestInfo.Http.httpRequest.Method, requestInfo.Http.httpRequest.Url);
}
iCount++;
}
//一次循环最多花100毫秒时间,超过了下次tick再处理
if ((DateTime.Now - beginTime).TotalMilliseconds >= 100)
{
TraceLog.Error("SyncHttpServerService.Update process request too slow, count {0} in this update, start {1} now {2}"
, iCount, beginTime.ToString("HH:mm:ss.fff"), DateTime.Now.ToString("HH:mm:ss.fff"));
break;
}
}
}
}
}