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.
167 lines
6.0 KiB
167 lines
6.0 KiB
1 month ago
|
// Copyright (C) 2016 by David Jeske, Barend Erasmus and donated to the public domain
|
||
|
|
||
|
using SimpleHttpServer;
|
||
|
|
||
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.IO;
|
||
|
using System.Linq;
|
||
|
using System.Net;
|
||
|
using System.Net.Sockets;
|
||
|
using System.Text;
|
||
|
using System.Threading;
|
||
|
using System.Threading.Tasks;
|
||
|
|
||
|
using Sog;
|
||
|
|
||
|
namespace SimpleHttpServer
|
||
|
{
|
||
|
|
||
|
public class HttpServer
|
||
|
{
|
||
|
#region Fields
|
||
|
|
||
|
private int Port;
|
||
|
private TcpListener Listener;
|
||
|
private HttpProcessor Processor;
|
||
|
private bool IsActive = true;
|
||
|
private uint httpCtxSeq = 1;
|
||
|
#endregion
|
||
|
|
||
|
//http处理线程结束钱等待时间,有些http response依赖其他服务器返回,没法立即处理,防止垃圾回收造成网络断线影响,增加这个时间
|
||
|
public int ProcessorThreadEndWaitTimeMs = 5000;
|
||
|
|
||
|
|
||
|
#region Public Methods
|
||
|
public HttpServer(int port, List<Route> routes)
|
||
|
{
|
||
|
this.Port = port;
|
||
|
this.Processor = new HttpProcessor();
|
||
|
|
||
|
foreach (var route in routes)
|
||
|
{
|
||
|
this.Processor.AddRoute(route);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
public void Listen()
|
||
|
{
|
||
|
this.Listener = new TcpListener(IPAddress.Any, this.Port);
|
||
|
this.Listener.Start();
|
||
|
|
||
|
while (this.IsActive)
|
||
|
{
|
||
|
TcpClient s = this.Listener.AcceptTcpClientAsync().Result;
|
||
|
//保证response的时候立即发送,usdk那边总是会出现callback我们支付服务器没有收到response就tcp reset了
|
||
|
s.NoDelay = true;
|
||
|
var httpCtx = new HttpContext(s) { id = httpCtxSeq++ };
|
||
|
|
||
|
//Task中使用sleep是不正确的用法,Task底层使用的是线程池,并不会由于调用Sleep把线程让出来,使用sleep导致能够执行的Task数量是受线程池大小限制 zouwei 2023/5/25
|
||
|
//new Thread性能在windows下非常的低,linux高些,后期业务量大了,可以考虑重构这个网络代码,比如用Sog.SessionListener代替,或者简单的用select模型都比这个靠谱,或者使用await异步
|
||
|
try
|
||
|
{
|
||
|
var t = new Thread(() => {
|
||
|
this.Processor.HandleClient(httpCtx);
|
||
|
var beginTime = DateTime.Now;
|
||
|
|
||
|
// 之前发现微软云经常出现tcp连接被RST导致http response没有发送成功, 看看是否线程内部异常
|
||
|
try
|
||
|
{
|
||
|
while (true)
|
||
|
{
|
||
|
if ((DateTime.Now - beginTime).TotalMilliseconds >= ProcessorThreadEndWaitTimeMs)
|
||
|
{
|
||
|
if (httpCtx != null && httpCtx.httpRequest != null)
|
||
|
{
|
||
|
TraceLog.Error("SyncHttpServerService request method {0} url {1} timeout!", httpCtx.httpRequest.Method, httpCtx.httpRequest.Url);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceLog.Error("SyncHttpServerService request timeout!");
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
Thread.Sleep(10);
|
||
|
if (httpCtx.isSendRes)
|
||
|
{
|
||
|
Thread.Sleep(200);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
//关闭一下,usdk那边总是会出现callback我们支付服务器没有收到response就tcp reset了
|
||
|
httpCtx.client.Close();
|
||
|
}
|
||
|
catch (Exception e)
|
||
|
{
|
||
|
TraceLog.Exception(e);
|
||
|
if (e.InnerException != null)
|
||
|
{
|
||
|
TraceLog.Exception(e.InnerException);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}, 1024 * 1024);
|
||
|
|
||
|
t.IsBackground = true;
|
||
|
t.Start();
|
||
|
}
|
||
|
catch (Exception ex)
|
||
|
{
|
||
|
TraceLog.Exception(ex);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// this formats the HTTP response...
|
||
|
public static void SendResponse(HttpContext httpCtx)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
HttpResponse response = httpCtx.httpResponse;
|
||
|
|
||
|
// default to text/html content type
|
||
|
if (!response.Headers.ContainsKey("Content-Type"))
|
||
|
{
|
||
|
response.Headers["Content-Type"] = "text/html";
|
||
|
}
|
||
|
|
||
|
response.Headers["Content-Length"] = response.Content.Length.ToString();
|
||
|
|
||
|
var stream = httpCtx.client.GetStream();
|
||
|
// Keep-Alive在1.0中默认关闭
|
||
|
Write(stream, string.Format("HTTP/1.0 {0} {1}\r\n", response.StatusCode, response.ReasonPhrase));
|
||
|
Write(stream, string.Join("\r\n", response.Headers.Select(x => string.Format("{0}: {1}", x.Key, x.Value))));
|
||
|
Write(stream, "\r\n\r\n");
|
||
|
|
||
|
if (response.Content == null)
|
||
|
{
|
||
|
response.Content = new byte[] { };
|
||
|
}
|
||
|
|
||
|
stream.Write(response.Content, 0, response.Content.Length);
|
||
|
}
|
||
|
catch (Exception e)
|
||
|
{
|
||
|
TraceLog.Exception(e);
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
httpCtx.isSendRes = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static void Write(Stream stream, string text)
|
||
|
{
|
||
|
byte[] bytes = Encoding.UTF8.GetBytes(text);
|
||
|
stream.Write(bytes, 0, bytes.Length);
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|