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 { /// public sealed class MiniServer { /// public MiniServer() { SynchronousIO = true; MaxRequest = 1024 * 1024 * 1024; } #region configuration /// 上下文处理程序。 /// 默认值:未指定 public Action Handler { get; set; } /// 捕获处理请求的异常。 /// 默认值:未指定 public Action CatchException { get; set; } /// 获取已指定的本地终结点。 public IPEndPoint IPEndPoint { get; private set; } /// 获取已监听的本地端口。 public int Port { get => GetPort(); } /// 入站超时毫秒数。指定 0 或 -1 时为无限大。 /// 默认值:0 public int InboundTimeout { get; set; } /// 出站超时毫秒数。指定 0 或 -1 时为无限大。 /// 默认值:0 public int OutboundTimeout { get; set; } /// SSL 证书。 internal X509Certificate SslCertificate { get; set; } /// SSL 域名。 internal string SslDomain { get; set; } /// SSL 协议。 internal SslProtocols SslProtocols { get; set; } /// 同步 IO 操作。 /// 默认值:True internal bool SynchronousIO { get; set; } /// 对响应体分块。 /// 默认值:False public bool Chunked { get; set; } /// 限制请求大小。 /// 默认值:1 GB。 public int MaxRequest { get; set; } /// 允许压缩。 public bool Compression { get; set; } #endregion #region launcher Thread _thread = null; /// 启动服务器。 /// /// /// /// 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); } /// 启动服务器。 /// /// /// 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); } /// 关闭服务器。 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 } }