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 m_outCallable; internal List m_requestList = new List(); List m_updateRequestList = new List(); 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 listconfig = new List(); 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; } } } } }