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.
|
|
using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading;
namespace Apewer.Web {
/// <summary></summary>
public sealed class MiniServer {
/// <summary></summary>
public MiniServer() { SynchronousIO = true; MaxRequest = 1024 * 1024 * 1024; }
#region configuration
/// <summary>上下文处理程序。</summary>
/// <remarks>默认值:未指定</remarks>
public Action<MiniContext> Handler { get; set; }
/// <summary>捕获处理请求的异常。</summary>
/// <remarks>默认值:未指定</remarks>
public Action<Exception> CatchException { get; set; }
/// <summary>获取已指定的本地终结点。</summary>
public IPEndPoint IPEndPoint { get; private set; }
/// <summary>获取已监听的本地端口。</summary>
public int Port { get => GetPort(); }
/// <summary>入站超时毫秒数。指定 0 或 -1 时为无限大。</summary>
/// <remarks>默认值:0</remarks>
public int InboundTimeout { get; set; }
/// <summary>出站超时毫秒数。指定 0 或 -1 时为无限大。</summary>
/// <remarks>默认值:0</remarks>
public int OutboundTimeout { get; set; }
/// <summary>SSL 证书。</summary>
internal X509Certificate SslCertificate { get; set; }
/// <summary>SSL 域名。</summary>
internal string SslDomain { get; set; }
/// <summary>SSL 协议。</summary>
internal SslProtocols SslProtocols { get; set; }
/// <summary>同步 IO 操作。</summary>
/// <remarks>默认值:True</remarks>
internal bool SynchronousIO { get; set; }
/// <summary>对响应体分块。</summary>
/// <remarks>默认值:False</remarks>
public bool Chunked { get; set; }
/// <summary>限制请求大小。</summary>
/// <remarks>默认值:1 GB。</remarks>
public int MaxRequest { get; set; }
/// <summary>允许压缩。</summary>
public bool Compression { get; set; }
#endregion
#region launcher
Thread _thread = null;
/// <summary>启动服务器。</summary>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentOutOfRangeException"></exception>
/// <exception cref="InvalidOperationException"></exception>
/// <exception cref="SocketException"></exception>
public void Run(int port = 0, bool await = true) { if (port < 0 || port > 65535) throw new ArgumentOutOfRangeException(nameof(port)); Run(new IPEndPoint(IPAddress.Any, port), await); }
/// <summary>启动服务器。</summary>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="InvalidOperationException"></exception>
/// <exception cref="SocketException"></exception>
public void Run(IPEndPoint ipEndpoint, bool await = true) { if (_socket != null) throw new InvalidOperationException("存在已启动的 Socket。"); if (ipEndpoint == null) throw new ArgumentNullException(nameof(ipEndpoint)); IPEndPoint = ipEndpoint;
var ipep = ipEndpoint; _socket = new Socket(ipep.AddressFamily, SocketType.Stream, ProtocolType.Tcp); _socket.Bind(ipep); _socket.Listen(500); var inTimeout = InboundTimeout; var outTimeout = OutboundTimeout; if (inTimeout > 0) _socket.ReceiveTimeout = inTimeout; if (outTimeout > 0) _socket.SendTimeout = outTimeout;
_thread = new Thread(Listen); _thread.IsBackground = true; _thread.Start();
if (await) while (_socket != null) Thread.Sleep(300); }
/// <summary>关闭服务器。</summary>
public void Shutdown() { var socket = _socket; if (socket != null) { try { socket.Shutdown(SocketShutdown.Both); } catch { } try { socket.Close(1); } catch { } _socket = null; } }
#endregion
#region listener
Socket _socket = null;
int GetPort() { var socket = _socket; if (socket == null) return 0; try { if (socket.LocalEndPoint is IPEndPoint ipep) { return ipep.Port; } } catch { } return 0; }
void Listen() { if (SynchronousIO) { while (_socket != null) { var socket = null as Socket; try { socket = _socket.Accept(); } catch { if (socket != null) { try { socket.Close(); } catch { } try { socket.Disconnect(false); } catch { } #if !NET20
try { socket.Dispose(); } catch { } #endif
} break; } if (socket != null) ThreadPool.QueueUserWorkItem(Process, socket); } } else { var e = new SocketAsyncEventArgs(); e.UserToken = this; e.Completed += (sender, arg) => Process(arg);
Socket dummy = null; Accept(e, ref dummy); } }
void Accept(SocketAsyncEventArgs e, ref Socket socket) { e.AcceptSocket = null; var async = false; try { async = _socket.AcceptAsync(e); } catch { if (socket != null) { try { socket.Close(); } catch { } socket = null; } return; } if (!async) Process(e); }
void Process(SocketAsyncEventArgs e) { var socket = null as Socket; if (e.SocketError == SocketError.Success) socket = e.AcceptSocket;
Accept(e, ref socket); if (socket == null) return; Process(socket); }
void Process(object obj) { var socket = obj as Socket; if (socket == null) return;
try { var conn = null as MiniConnection; conn = new MiniConnection(this, socket); conn.BeginRead(); } catch (Exception ex) { Shutdown(); Logger.Web.Exception(ex, this); CatchException?.Invoke(ex); return; } }
#endregion
}
}
|