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
}
}