├── Demo ├── Nancy.Demo2 │ ├── MyStatusHandler.cs │ ├── Views │ │ ├── Test.cshtml │ │ ├── Home │ │ │ └── Index.cshtml │ │ └── Status │ │ │ └── 404.cshtml │ ├── BootStrapper.cs │ ├── Startup.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── RazorConfig.cs │ ├── Web.Debug.config │ ├── Web.config │ ├── MainModule.cs │ ├── Web.Release.config │ ├── SiteRootPath.cs │ ├── Adapter.cs │ └── Nancy.Demo2.csproj ├── AspTest │ ├── aspx │ │ ├── Default.aspx │ │ └── Default.aspx.cs │ ├── Adapter.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ └── AspTest.csproj └── WebSocket.Demo2 │ ├── Properties │ └── AssemblyInfo.cs │ ├── index.html │ ├── WebSocket.Demo2.csproj │ └── Adapter.cs ├── OwinDog ├── runtime │ └── native │ │ └── libuv │ │ ├── oth │ │ └── libuv.dylib │ │ ├── lin │ │ └── x32 │ │ │ └── libuv.so.1 │ │ └── win │ │ └── x32 │ │ └── libuv.dll ├── Service │ ├── WriteParam.cs │ ├── CustomeAsyncResult.cs │ ├── RequestDataFactory.cs │ ├── RequestCheck.cs │ ├── ApplicationInfo.cs │ ├── ActionQueue.cs │ ├── ActionStoreManage.cs │ ├── SimpleThreadPool.cs │ └── HttpMimeTypeManage.cs ├── OwinEngine │ ├── OwinHttpWorkerManage.cs │ ├── OwinAdapterManage.cs │ ├── ISocket.cs │ ├── HeaderDictionary.cs │ ├── OwinAdapter.cs │ ├── OwinTask.cs │ └── OwinRequestStream.cs ├── ProgMain.cs ├── Model │ ├── UvPipeHandle.cs │ ├── LoopHandle.cs │ ├── ListenHandle.cs │ ├── AsyncHandle.cs │ ├── UvPipeStream.cs │ ├── ShutdownHandle.cs │ ├── HandleBase.cs │ ├── WriteHandle.cs │ └── UvStreamHandle.cs ├── Properties │ └── AssemblyInfo.cs ├── Util │ ├── HttpCodeUtil.cs │ ├── SystemUtil.cs │ ├── UrlDeCode.cs │ ├── WebSocketReciveDataParse.cs │ └── AssemblyUtils.cs └── OwinDog.csproj ├── Dog ├── App.config ├── Properties │ └── AssemblyInfo.cs └── Dog.csproj ├── Owin.WebSocket ├── packages.config ├── WebSocketRouteAttribute.cs ├── Handlers │ ├── SendContext.cs │ ├── IWebSocket.cs │ ├── NetWebSocket.cs │ └── OwinWebSocket.cs ├── Properties │ └── AssemblyInfo.cs ├── WebSocketConnectionMiddleware.cs ├── Extensions │ ├── OwinExtension.cs │ └── TaskQueue.cs └── Owin.WebSocket.csproj ├── README.md ├── Owin.AspEngine ├── Properties │ └── AssemblyInfo.cs ├── AspEngine │ ├── AspRequestData.cs │ ├── AspRequestBroker.cs │ ├── AspApplicationHost.cs │ └── AspNet.cs └── Owin.AspEngine.csproj └── .gitignore /Demo/Nancy.Demo2/MyStatusHandler.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuzd/OwinDog/HEAD/Demo/Nancy.Demo2/MyStatusHandler.cs -------------------------------------------------------------------------------- /OwinDog/runtime/native/libuv/oth/libuv.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuzd/OwinDog/HEAD/OwinDog/runtime/native/libuv/oth/libuv.dylib -------------------------------------------------------------------------------- /OwinDog/runtime/native/libuv/lin/x32/libuv.so.1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuzd/OwinDog/HEAD/OwinDog/runtime/native/libuv/lin/x32/libuv.so.1 -------------------------------------------------------------------------------- /OwinDog/runtime/native/libuv/win/x32/libuv.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuzd/OwinDog/HEAD/OwinDog/runtime/native/libuv/win/x32/libuv.dll -------------------------------------------------------------------------------- /Demo/Nancy.Demo2/Views/Test.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 参数是:@Model.abc 8 | 9 | 10 | -------------------------------------------------------------------------------- /Dog/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Demo/Nancy.Demo2/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Index 5 | 6 | 7 | Hello.....
8 | 9 | 10 | -------------------------------------------------------------------------------- /Demo/Nancy.Demo2/Views/Status/404.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 404, Can't find.... 8 | 9 | 10 | -------------------------------------------------------------------------------- /OwinDog/Service/WriteParam.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Service 4 | { 5 | public sealed class WriteParam 6 | { 7 | public byte[] Buffer; 8 | 9 | public int Offset; 10 | 11 | public int Length; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Owin.WebSocket/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Owin.WebSocket/WebSocketRouteAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Owin.WebSocket 4 | { 5 | [AttributeUsage(AttributeTargets.Class, AllowMultiple=true)] 6 | public class WebSocketRouteAttribute: Attribute 7 | { 8 | public string Route { get; set; } 9 | 10 | public WebSocketRouteAttribute(string route) 11 | { 12 | Route = route; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Demo/Nancy.Demo2/BootStrapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using Nancy.Session; 6 | namespace Nancy.Demo2 7 | { 8 | public class BootStrapper : DefaultNancyBootstrapper 9 | { 10 | protected override void ApplicationStartup(TinyIoc.TinyIoCContainer container, Bootstrapper.IPipelines pipelines) 11 | { 12 | //启用session 13 | CookieBasedSessions.Enable(pipelines); 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /OwinDog/OwinEngine/OwinHttpWorkerManage.cs: -------------------------------------------------------------------------------- 1 | using Service; 2 | 3 | namespace OwinEngine 4 | { 5 | public static class OwinHttpWorkerManage 6 | { 7 | public static void OwinHttpProcess(OwinSocket owinSocket) 8 | { 9 | new OwinHttpWorker(null).Start(owinSocket); 10 | } 11 | 12 | public static void Start(OwinSocket owinSocket, byte[] array) 13 | { 14 | new OwinHttpWorker(array).Start(owinSocket); 15 | } 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /Demo/AspTest/aspx/Default.aspx: -------------------------------------------------------------------------------- 1 | <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 | 14 |
15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /OwinDog/ProgMain.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Net.Sockets; 7 | using System.Reflection; 8 | using System.Runtime.CompilerServices; 9 | using System.Runtime.InteropServices; 10 | using System.Text; 11 | using System.Threading; 12 | using System.Threading.Tasks; 13 | using System.Timers; 14 | using Model; 15 | using OwinEngine; 16 | using Service; 17 | using Util; 18 | 19 | namespace OwinDog 20 | { 21 | public class ProgMain 22 | { 23 | 24 | 25 | } 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /Owin.WebSocket/Handlers/SendContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.WebSockets; 3 | using System.Threading; 4 | 5 | namespace Owin.WebSocket.Handlers 6 | { 7 | internal class SendContext 8 | { 9 | public ArraySegment Buffer; 10 | public bool EndOfMessage; 11 | public WebSocketMessageType Type; 12 | public CancellationToken CancelToken; 13 | 14 | public SendContext(ArraySegment buffer, bool endOfMessage, WebSocketMessageType type, CancellationToken cancelToken) 15 | { 16 | Buffer = buffer; 17 | EndOfMessage = endOfMessage; 18 | Type = type; 19 | CancelToken = cancelToken; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /Demo/AspTest/Adapter.cs: -------------------------------------------------------------------------------- 1 | 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Net.WebSockets; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Owin.AspEngine; 8 | 9 | namespace AspTest 10 | { 11 | 12 | /// 13 | /// owin/owindog For OWIN 接口类 14 | /// 15 | public class Adapter 16 | { 17 | 18 | 19 | /// 20 | /// OWIN适配器的主函数 21 | /// 22 | /// 23 | /// 24 | public Task OwinMain(IDictionary env) 25 | { 26 | 27 | return AspNet.Process(env); 28 | } 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | } 38 | 39 | 40 | 41 | } 42 | -------------------------------------------------------------------------------- /OwinDog/Model/UvPipeHandle.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace Model 3 | { 4 | 5 | public class UvPipeHandle : UvStreamHandle 6 | { 7 | public int PipePendingCount() 8 | { 9 | return LibUv.PipePendingCount(this); 10 | } 11 | 12 | public void PipeBind(string text) 13 | { 14 | LibUv.PipeBind(this, text); 15 | } 16 | 17 | /// 18 | /// Init 19 | /// 20 | /// 21 | /// 若是 IPC 或命名管道,应该设置为 true 22 | public void Init(LoopHandle loopHandle, bool flag = true) 23 | { 24 | Init(loopHandle.LibUv, loopHandle.LibUv.NamePipeHandleSize, loopHandle.LoopRunThreadId); 25 | LibUv.PipeInit(loopHandle, this, flag); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Demo/Nancy.Demo2/Startup.cs: -------------------------------------------------------------------------------- 1 | using Owin; 2 | using Nancy; 3 | 4 | namespace Nancy.Demo2 5 | { 6 | 7 | /// 8 | /// 支持NancyFx的OWIN启动类 9 | /// MS'OWIN 标准的宿主都需要一个启动类 10 | /// 11 | public class Startup 12 | { 13 | public Startup() { 14 | 15 | // 显示详细的异常信息 16 | StaticConfiguration.DisableErrorTraces = false; 17 | 18 | //增加Nancy处理json字串的长度 19 | //Nancy.Json.JsonSettings.MaxJsonLength = int.MaxValue; 20 | 21 | // 其它初始化动作 22 | // ........ 23 | } 24 | 25 | public void Configuration(IAppBuilder builder) 26 | { 27 | //将 Nancy(中间件)添加到Microsoft.Owin处理环节中 28 | //////////////////////////////////////////////////// 29 | builder.UseNancy(); 30 | 31 | } 32 | } 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /Owin.WebSocket/Handlers/IWebSocket.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.WebSockets; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using Owin.WebSocket.Extensions; 6 | 7 | namespace Owin.WebSocket.Handlers 8 | { 9 | internal interface IWebSocket 10 | { 11 | TaskQueue SendQueue { get; } 12 | Task SendText(ArraySegment data, bool endOfMessage, CancellationToken cancelToken); 13 | Task SendBinary(ArraySegment data, bool endOfMessage, CancellationToken cancelToken); 14 | Task Send(ArraySegment data, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancelToken); 15 | Task Close(WebSocketCloseStatus closeStatus, string closeDescription, CancellationToken cancelToken); 16 | Task, WebSocketMessageType>> ReceiveMessage(byte[] buffer, CancellationToken cancelToken); 17 | WebSocketCloseStatus? CloseStatus { get; } 18 | string CloseStatusDescription { get; } 19 | } 20 | } -------------------------------------------------------------------------------- /Demo/AspTest/aspx/Default.aspx.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text.RegularExpressions; 5 | using System.Web; 6 | using System.Web.UI; 7 | using System.Web.UI.WebControls; 8 | 9 | public partial class _Default : System.Web.UI.Page 10 | { 11 | protected void Page_Load(object sender, EventArgs e) 12 | { 13 | this.ipTxt.Value = GetIp(); 14 | } 15 | 16 | public string GetIp() 17 | { 18 | string result = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]; 19 | result += "," + HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; 20 | 21 | result += "," + HttpContext.Current.Request.UserHostAddress; 22 | 23 | if (string.IsNullOrEmpty(result) || !IsIPv4(result)) 24 | { 25 | return "127.0.0.1"; 26 | } 27 | 28 | return result; 29 | } 30 | 31 | public bool IsIPv4(string ip) 32 | { 33 | return Regex.IsMatch(ip, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$"); 34 | } 35 | } -------------------------------------------------------------------------------- /Demo/Nancy.Demo2/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的常规信息通过下列特性集 6 | // 控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("Nancy.Demo2")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Nancy.Demo2")] 13 | [assembly: AssemblyCopyright("版权所有(C) 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 会使此程序集中的类型 18 | // 对 COM 组件不可见。如果需要从 COM 访问此程序集中的某个类型, 19 | // 请针对该类型将 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("55b519eb-63ab-42fc-b5fb-04ec62dce486")] 24 | 25 | // 程序集的版本信息由下列四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 内部版本号 30 | // 修订号 31 | // 32 | // 可以指定所有这些值,也可以使用“修订号”和“内部版本号”的默认值, 33 | // 方法是按如下所示使用“*”: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /Demo/AspTest/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的一般信息由以下 6 | // 控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("AspTest")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("AspTest")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | //将 ComVisible 设置为 false 将使此程序集中的类型 18 | //对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型, 19 | //请将此类型的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("83c619a2-4ae4-4029-945b-657f7159396e")] 24 | 25 | // 程序集的版本信息由下列四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 生成号 30 | // 修订号 31 | // 32 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, 33 | // 方法是按如下所示使用“*”: : 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Demo/Nancy.Demo2/RazorConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Nancy.ViewEngines.Razor; 4 | 5 | namespace Nancy.Demo2 6 | { 7 | 8 | 9 | /// 10 | /// Razor配置,如果你需要使用 cshtml,这个配置比较重要,当然,也可以在这儿加入其它的类 11 | /// 12 | public class RazorConfig : IRazorConfiguration 13 | { 14 | 15 | /// 16 | /// 需加载的程序集列表 17 | /// 18 | /// 19 | public IEnumerable GetAssemblyNames() 20 | { 21 | //加了这句,才能处理 cshtml 22 | yield return "System.Web.Razor"; 23 | } 24 | 25 | /// 26 | /// 需要添加到cshtml中的名字空间 27 | /// 28 | /// 29 | public IEnumerable GetDefaultNamespaces() 30 | { 31 | yield return "System.Web.Razor"; 32 | } 33 | 34 | /// 35 | /// 是否自动引用model名字空间 36 | /// 37 | public bool AutoIncludeModelNamespace 38 | { 39 | get { return true; } 40 | } 41 | } 42 | 43 | 44 | } 45 | -------------------------------------------------------------------------------- /OwinDog/OwinEngine/OwinAdapterManage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Service; 3 | 4 | namespace OwinEngine 5 | { 6 | 7 | public sealed class OwinAdapterManage 8 | { 9 | private static readonly OwinManager _owinManager = new OwinManager(OnOwinCallCompleteCallback); 10 | 11 | public bool Process(RequestData requestData) 12 | { 13 | return _owinManager != null && _owinManager.Process(requestData); 14 | } 15 | 16 | /// 17 | /// 如果Connection Close掉了 关闭tcp 否则保持Tcp socket长连接 18 | /// 19 | /// 20 | /// 21 | private static void OnOwinCallCompleteCallback(RequestData req, bool iskeep) 22 | { 23 | if (!iskeep || !req.IsKeepAlive())//Connection 是否Close掉了 24 | { 25 | req.Socket.Dispose(); 26 | req.SaveToPoll(); 27 | return; 28 | } 29 | OwinHttpWorkerManage.Start((OwinSocket)req.Socket, req._preLoadedBody); 30 | req.SaveToPoll(); 31 | } 32 | 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Demo/WebSocket.Demo2/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的常规信息通过以下 6 | // 特性集控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("WebSocket.Demo2")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("WebSocket.Demo2")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 使此程序集中的类型 18 | // 对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型, 19 | // 则将该类型上的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("a0ae50ad-793e-408e-9144-c08a016b04d6")] 24 | 25 | // 程序集的版本信息由下面四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 生成号 30 | // 修订号 31 | // 32 | // 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, 33 | // 方法是按如下所示使用“*”: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Owin.WebSocket/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的一般信息由以下 6 | // 控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("Owin.WebSocket")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("Owin.WebSocket")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | //将 ComVisible 设置为 false 将使此程序集中的类型 18 | //对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型, 19 | //请将此类型的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("ed2ee07f-39ca-4f87-9346-e47ed3b5f4e0")] 24 | 25 | // 程序集的版本信息由下列四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 生成号 30 | // 修订号 31 | // 32 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, 33 | // 方法是按如下所示使用“*”: : 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Demo/Nancy.Demo2/Web.Debug.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 30 | 31 | -------------------------------------------------------------------------------- /Demo/Nancy.Demo2/Web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Demo/Nancy.Demo2/MainModule.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Nancy; 3 | 4 | 5 | 6 | namespace Nancy.Demo2 7 | { 8 | 9 | public class MainModule : NancyModule 10 | { 11 | 12 | /// 13 | /// 构造函数 14 | /// 15 | public MainModule() 16 | { 17 | 18 | //在构造函数中进行路由配置 19 | 20 | Get["/"] = IndexPage; 21 | Get["/test/{abc}"] = ToTest; 22 | Get["/test"] = _ => "this test....."; 23 | Get["/get"] = _ => Request.Session["kkkk"] == null ? "nonoono" : "okokok"; 24 | Get["/set"] = _ => { Request.Session["kkkk"] = "okkkk"; return "set ok."; }; 25 | 26 | } 27 | 28 | 29 | 30 | /// 31 | /// 主页的实现方法 32 | /// 33 | /// 34 | /// 35 | private dynamic IndexPage(dynamic d) 36 | { 37 | //显示cshtml页 38 | return View["Home/Index"]; 39 | } 40 | 41 | 42 | 43 | 44 | 45 | private dynamic ToTest(dynamic d) 46 | { 47 | return View["Test", d]; 48 | } 49 | 50 | 51 | 52 | } 53 | 54 | 55 | 56 | 57 | 58 | } -------------------------------------------------------------------------------- /Demo/Nancy.Demo2/Web.Release.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 31 | 32 | -------------------------------------------------------------------------------- /OwinDog/Service/CustomeAsyncResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Runtime.CompilerServices; 4 | using System.Threading; 5 | 6 | namespace Service 7 | { 8 | 9 | 10 | 11 | public sealed class CustomeAsyncResult : IAsyncResult 12 | { 13 | public CustomeAsyncResult(object obj) 14 | { 15 | AsyncState = obj; 16 | AsyncWaitHandle = new AutoResetEvent(false); 17 | } 18 | 19 | 20 | public byte[] RecvBuffer { get; set; } 21 | 22 | 23 | public int RecvLength { get; set; } 24 | 25 | 26 | 27 | public int RecvOffset { get; set; } 28 | 29 | public object AsyncState { get; set; } 30 | 31 | public AsyncCallback UserCallbackFunc { get; set; } 32 | 33 | 34 | public WaitHandle AsyncWaitHandle { get; set; } 35 | 36 | public int RealRecvSize { get; set; } 37 | 38 | 39 | public bool IsCompleted { get; set; } 40 | 41 | 42 | internal bool SocketIsErrOrClose { get; set; } 43 | 44 | 45 | 46 | internal bool SocketIsTimeOut{ get; set; } 47 | 48 | public bool CompletedSynchronously { 49 | get { return false; } 50 | } 51 | 52 | 53 | 54 | 55 | } 56 | 57 | 58 | } 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](https://img.shields.io/badge/platform-dotnet-red.svg) ![](https://img.shields.io/badge/language-CSharp-orange.svg) 2 | [![Support](https://img.shields.io/badge/support-NetCore-blue.svg?style=flat)](https://www.microsoft.com/net/core) 3 | [![Weibo](https://img.shields.io/badge/博客园-@鱼东东-yellow.svg?style=flat)](http://www.cnblogs.com/yudongdong) 4 | [![GitHub stars](https://img.shields.io/github/stars/yuzd/OwinDog.svg)](https://github.com/yuzd/OwinDog/stargazers) 5 | 6 | 7 | # 什么是 OWIN ? 8 |   .OWIN 的全称是 "Open Web Interface for .NET", OWIN 在 .NET Web 服务器和 .NET Web 应用之间定义了一套标准的接口, 9 | 其目的是为了实现服务器与应用之间的解耦, 鼓励为 .NET Web 应用开发简单模块。 10 | 11 | 12 | # OwinDog 是一款支持OWIN标准的WEB应用的高性能的HTTP服务器,有如下特点: 13 | 14 | 1,跨平台:支持windows、linux等常用操作系统(后者由mono支持); 15 | 16 | 2,超轻量:功能单一而明确:除了静态文件由自身处理外,其它的应用逻辑直接交给用户处理; 17 | 18 | 3,高性能:底层基于 libuv 开发,是完全的异步、非阻塞、事件驱动模型,上层代码也经过了高度优化;libuv是NodeJs的基础库,libuv 是一个高性能事件驱动的程序库,封装了 Windows 和 Unix 平台一些底层特性,为开发者提供了统一的 API,libuv 采用了异步 (asynchronous), 事件驱动 (event-driven)的编程风格, 其主要任务是为开人员提供了一套事件循环和基于I/O(或其他活动)通知的回调函数, libuv 提供了一套核心的工具集, 例如定时器, 非阻塞网络编程的支持, 异步访问文件系统, 子进程以及其他功能,关于libuv的更多内容推荐参考电子书 http://www.nowx.org/uvbook/ 。 19 | 20 | 21 | # 测试访问aspx的demo 22 | [aspx demo](https://files.cnblogs.com/files/yudongdong/%E6%B5%8B%E8%AF%95aspx.zip) 23 | 24 | 25 | 欢迎测试,如果你有什么问题,请提交Issue或者加入QQ群433685124 26 | -------------------------------------------------------------------------------- /OwinDog/Model/LoopHandle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | namespace Model 5 | { 6 | 7 | public class LoopHandle : HandleBase 8 | { 9 | public void Stop() 10 | { 11 | LibUv.Stop(this); 12 | } 13 | 14 | /// 15 | /// 把监视器和loop联系起来 16 | /// 17 | /// 18 | public void Init(LibUv libUv) 19 | { 20 | base.Init(libUv, libUv.GetUvLoopSize(), Thread.CurrentThread.ManagedThreadId); 21 | LibUv.Init(this);//loop init 22 | } 23 | 24 | 25 | public int Start(int num = 0/*UV_RUN_DEFAULT*/) 26 | { 27 | return LibUv.Run(this, num); 28 | } 29 | 30 | protected override unsafe bool ReleaseHandle() 31 | { 32 | IntPtr ptr = handle; 33 | if (ptr != IntPtr.Zero) 34 | { 35 | IntPtr intPtr = *(IntPtr*)((void*)ptr); 36 | try 37 | { 38 | LibUv.LoopClose(this); 39 | } 40 | catch 41 | { 42 | //ignore 43 | } 44 | handle = IntPtr.Zero; 45 | FreeHandle(ptr, intPtr); 46 | } 47 | return true; 48 | } 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Demo/Nancy.Demo2/SiteRootPath.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************** 2 | * 为NancyFx提供应用程序根目录绝对路径的类 3 | * --------------------------------------------------------------- 4 | * 要点:类名可以随便取,但必需继续自 IRootPathProvider 5 | * 整个应用程序(网站)只能有一个这样的类 6 | * ****************************************************************/ 7 | 8 | 9 | #region 10 | 11 | using System; 12 | using Nancy; 13 | using System.IO; 14 | 15 | #endregion 16 | 17 | 18 | namespace Nancy.Demo2 19 | { 20 | 21 | /// 22 | /// 提供网站物理路径的类 23 | /// 24 | public class SiteRootPath : IRootPathProvider 25 | { 26 | 27 | /************************************************************** 28 | * owindog Owin Server 默认情况下 29 | * 网站是放在 owindog 进程所在文件夹下的site/wwwroot中的 30 | * ---------------------------------------------------------- 31 | * 如果你把 NancyFx 的 Views 页放在其它的地方,应该作相应修改 32 | *******************************************************************/ 33 | 34 | /// 35 | /// 网站根文件夹物理路径(for owindog) 36 | /// 37 | static readonly string _RootPath = AppDomain.CurrentDomain.GetData(".appPath").ToString(); 38 | 39 | 40 | /// 41 | /// 获取网站或WEB应用的根文件夹的物理路径 42 | /// 43 | /// 44 | public string GetRootPath() 45 | { 46 | return _RootPath; 47 | 48 | } 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Dog/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Dog")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Dog")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("3b51c35f-ef88-493a-8183-4cfeca20f263")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Owin.AspEngine/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Owin.AspEngine")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("OwinDog")] 12 | [assembly: AssemblyProduct("Owin.AspEngine")] 13 | [assembly: AssemblyCopyright("Copyright ©nainaigu 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("e044c158-1347-4a46-bb69-fe7403d2eb0e")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /OwinDog/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("OwinDog")] 9 | [assembly: AssemblyDescription("www.OwinDog.com")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("OwinDog")] 12 | [assembly: AssemblyProduct("OwinDog")] 13 | [assembly: AssemblyCopyright("Copyright ©nainaigu 2016")] 14 | [assembly: AssemblyTrademark("OwinDog")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("38fd2383-56a2-408d-8cbf-1e175f8d6488")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0")] 37 | -------------------------------------------------------------------------------- /OwinDog/Service/RequestDataFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace Service 6 | { 7 | /// 8 | /// 循环利用 9 | /// 10 | internal static class RequestDataFactory 11 | { 12 | private const int MaxSize = 10000; 13 | 14 | private static readonly Queue AQueue = new Queue(MaxSize); 15 | 16 | /// 17 | /// 获取 18 | /// 19 | /// 20 | public static byte[] Create() 21 | { 22 | byte[] result; 23 | lock (AQueue) 24 | { 25 | if (AQueue.Count < 1) 26 | { 27 | //TcpClient.ReceiveBufferSize Property The size of the receive buffer, in bytes. The default value is 8192 bytes. 28 | result = new byte[8192]; 29 | } 30 | else 31 | { 32 | result = AQueue.Dequeue(); 33 | } 34 | } 35 | return result; 36 | } 37 | 38 | /// 39 | /// 回收 40 | /// 41 | /// 42 | public static void Recover(byte[] array) 43 | { 44 | if (array == null || array.Length != 8192 || AQueue.Count > MaxSize) 45 | { 46 | return; 47 | } 48 | lock (AQueue) 49 | { 50 | AQueue.Enqueue(array); 51 | } 52 | } 53 | 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /OwinDog/OwinEngine/ISocket.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net.Sockets; 5 | using System.Runtime.CompilerServices; 6 | using System.Text; 7 | 8 | namespace OwinEngine 9 | { 10 | 11 | public interface ISocket 12 | { 13 | /// 14 | /// 获取访问者IP地址 15 | /// 16 | /// 17 | string GetRemoteIpAddress(); 18 | 19 | /// 20 | /// 获取访问者的Ip端口 21 | /// 22 | /// 23 | int GetRemoteIpPort(); 24 | 25 | /// 26 | /// 获取本地的IP地址 27 | /// 28 | /// 29 | string LocalIpAddress(); 30 | 31 | /// 32 | /// 获取本地的IP端口 33 | /// 34 | /// 35 | int LocalIpPort(); 36 | 37 | /// 38 | /// 写操作 39 | /// 40 | /// 41 | /// 42 | void Read(Action callBack, object state); 43 | 44 | /// 45 | /// 读操作 46 | /// 47 | /// 48 | /// 49 | /// 50 | void Write(byte[] array, Action callback, object otherState); 51 | 52 | void WriteForPost(byte[] headDomain, byte[] body, Action callback, object otherState); 53 | 54 | void Dispose(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /OwinDog/Model/ListenHandle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | 4 | namespace Model 5 | { 6 | 7 | /// 8 | /// lib uv 的 tcp handle 9 | /// 10 | public class ListenHandle : UvStreamHandle 11 | { 12 | public LoopHandle Loop { get; set; } 13 | 14 | 15 | 16 | public void TcpBind(IPEndPoint iPEndPoint) 17 | { 18 | string text = iPEndPoint.Address.ToString(); 19 | LibUv.Addr addr; 20 | Exception ex; 21 | LibUv.Ip4Address(text, iPEndPoint.Port, out addr, out ex); 22 | if (ex != null) 23 | { 24 | Exception ex2; 25 | LibUv.Ip6Address(text, iPEndPoint.Port, out addr, out ex2); 26 | if (ex2 != null) 27 | { 28 | throw ex; 29 | } 30 | } 31 | LibUv.TcpBind(this, ref addr, 0); 32 | } 33 | 34 | public void TcpNodealy(bool flag) 35 | { 36 | LibUv.TcpNodealy(this, flag); 37 | } 38 | 39 | public void Init(LoopHandle loopHandle, Action, object> asyncSendUserPostAction) 40 | { 41 | base.Init(loopHandle.LibUv, loopHandle.LibUv.TcpHandleSize, loopHandle.LoopRunThreadId); 42 | LibUv.TcpInit(loopHandle, this); 43 | Loop=loopHandle; 44 | _postAsync = asyncSendUserPostAction; 45 | } 46 | 47 | public void TcpBind(string ipString, int port) 48 | { 49 | IPEndPoint iPEndPoint = new IPEndPoint(IPAddress.Parse(ipString), port); 50 | TcpBind(iPEndPoint); 51 | } 52 | 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Owin.AspEngine/AspEngine/AspRequestData.cs: -------------------------------------------------------------------------------- 1 | namespace Owin.AspEngine 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Runtime.CompilerServices; 6 | 7 | [Serializable] 8 | internal class AspRequestData 9 | { 10 | public AspRequestData(int reqid, IDictionary env) 11 | { 12 | this.RequestId = reqid; 13 | this.RequestHttpHeader = env["owin.RequestHeaders"] as IDictionary; 14 | this.QueryString = env["owin.RequestQueryString"] as string; 15 | this.Verb = env["owin.RequestMethod"] as string; 16 | this.Protocol = env["owin.RequestProtocol"] as string; 17 | this.UrlPath = env["owin.RequestPath"] as string; 18 | this.RemoteAddress = env["server.RemoteIpAddress"] as string; 19 | this.RemotePort = int.Parse((string) env["server.RemotePort"]); 20 | this.LocalAddress = env["server.LocalIpAddress"] as string; 21 | this.LocalPort = int.Parse((string) env["server.LocalPort"]); 22 | } 23 | 24 | public string LocalAddress { get; private set; } 25 | 26 | public int LocalPort { get; private set; } 27 | 28 | public string Protocol { get; private set; } 29 | 30 | public string QueryString { get; private set; } 31 | 32 | public string RemoteAddress { get; private set; } 33 | 34 | public int RemotePort { get; private set; } 35 | 36 | /// 37 | /// 请求头 38 | /// 39 | public IDictionary RequestHttpHeader { get; private set; } 40 | 41 | public int RequestId { get; private set; } 42 | 43 | public string UrlPath { get; private set; } 44 | 45 | public string Verb { get; private set; } 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /OwinDog/Model/AsyncHandle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace Model 5 | { 6 | /// 7 | /// uv_async is the only thread-safe facility that libuv has. 8 | /// 9 | public class AsyncHandle : HandleBase 10 | { 11 | private static readonly LibUv.AsyncInit_callback _uv_async_cb = AsyncCb; 12 | 13 | private Action _callback; 14 | 15 | /// 16 | /// uv_asyncがやってくれるのは、async_cbを呼ぶことだけなので、 17 | /// なにかデータを渡したいときは別途、 18 | /// pthread_mutexなどを使用して共有データをわたすように自分でよしなにやるかんじですね 19 | /// 20 | public void AsyncSend() 21 | { 22 | LibUv.AsyncSend(this); 23 | } 24 | 25 | public void dispose() 26 | { 27 | Dispose(); 28 | ReleaseHandle(); 29 | } 30 | 31 | private static unsafe void AsyncCb(IntPtr ptrUvAsyncHandle) 32 | { 33 | AsyncHandle asyncHandlea = (AsyncHandle)GCHandle.FromIntPtr(*(IntPtr*)((void*)ptrUvAsyncHandle)).Target; 34 | if (asyncHandlea == null) 35 | { 36 | return; 37 | } 38 | try 39 | { 40 | asyncHandlea._callback(); 41 | } 42 | catch 43 | { 44 | //ignore 45 | } 46 | } 47 | 48 | /// 49 | /// 为loop注册了一个异步消息监听器 其他线程就可以通过async监视器给主线程发送消息 50 | /// 51 | /// 52 | /// 53 | public void Init(LoopHandle loopHandle, Action cb) 54 | { 55 | base.Init(loopHandle.LibUv, loopHandle.LibUv.HandSize(LibUv.HandleType.UV_ASYNC), loopHandle.LoopRunThreadId); 56 | _callback = cb; 57 | LibUv.AsyncInit(loopHandle, this, _uv_async_cb); 58 | } 59 | 60 | 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /OwinDog/Model/UvPipeStream.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Model 4 | { 5 | 6 | public class UvPipeStream : HandleBase 7 | { 8 | private static readonly LibUv.PipeConnect_Callback _uv_shutdown_cb = UvShutdownCb; 9 | 10 | private Action _callback; 11 | 12 | private object _state; 13 | public void Init(LoopHandle loopHandle) 14 | { 15 | base.Init(loopHandle.LibUv, loopHandle.LibUv.ConnectReqSize, loopHandle.LoopRunThreadId); 16 | } 17 | 18 | 19 | public void PipeConnect(UvPipeHandle uvPipeHandle, string text, Action callback, object state) 20 | { 21 | _callback = callback; 22 | _state = state; 23 | Alloc(); 24 | LibUv.PipeConnect(this, uvPipeHandle, text, _uv_shutdown_cb); 25 | } 26 | 27 | protected override bool ReleaseHandle() 28 | { 29 | _Close_Callback(handle); 30 | handle = IntPtr.Zero; 31 | return true; 32 | } 33 | private static void UvShutdownCb(IntPtr ptrReq, int status) 34 | { 35 | UvPipeStream uvPipeStream = GetObjectFromHandel(ptrReq); 36 | uvPipeStream.DoDispose(); 37 | 38 | Exception arg = null; 39 | if (status < 0) 40 | { 41 | uvPipeStream.LibUv.GetException(status, out arg); 42 | } 43 | try 44 | { 45 | uvPipeStream._callback(uvPipeStream, status, arg, uvPipeStream._state); 46 | } 47 | catch (Exception ex) 48 | { 49 | throw ex; 50 | } 51 | finally 52 | { 53 | uvPipeStream._callback = null; 54 | uvPipeStream._state = null; 55 | } 56 | } 57 | 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Owin.WebSocket/WebSocketConnectionMiddleware.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text.RegularExpressions; 3 | using System.Threading.Tasks; 4 | using Microsoft.Owin; 5 | using Microsoft.Practices.ServiceLocation; 6 | using System; 7 | 8 | namespace Owin.WebSocket 9 | { 10 | public class WebSocketConnectionMiddleware : OwinMiddleware where T : WebSocketConnection 11 | { 12 | private readonly Regex mMatchPattern; 13 | private readonly IServiceLocator mServiceLocator; 14 | 15 | public WebSocketConnectionMiddleware(OwinMiddleware next, IServiceLocator locator) 16 | : base(next) 17 | { 18 | mServiceLocator = locator; 19 | } 20 | 21 | public WebSocketConnectionMiddleware(OwinMiddleware next, IServiceLocator locator, Regex matchPattern) 22 | : this(next, locator) 23 | { 24 | mMatchPattern = matchPattern; 25 | } 26 | 27 | public override Task Invoke(IOwinContext context) 28 | { 29 | var matches = new Dictionary(); 30 | 31 | if (mMatchPattern != null) 32 | { 33 | var match = mMatchPattern.Match(context.Request.Path.Value); 34 | if(!match.Success) 35 | return Next.Invoke(context); 36 | 37 | for (var i = 1; i <= match.Groups.Count; i++) 38 | { 39 | var name = mMatchPattern.GroupNameFromNumber(i); 40 | var value = match.Groups[i]; 41 | matches.Add(name, value.Value); 42 | } 43 | } 44 | 45 | T socketConnection; 46 | if(mServiceLocator == null) 47 | socketConnection = Activator.CreateInstance(); 48 | else 49 | socketConnection = mServiceLocator.GetInstance(); 50 | 51 | return socketConnection.AcceptSocketAsync(context, matches); 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /OwinDog/Model/ShutdownHandle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Model 4 | { 5 | public class ShutdownHandle : HandleBase 6 | { 7 | 8 | private static readonly LibUv.ShutDown_Callback _ShutDown_Callback = new LibUv.ShutDown_Callback(ShutDown_Callback); 9 | 10 | private Action _callBack; 11 | 12 | private object _state; 13 | 14 | public void Init(LoopHandle loopHandle) 15 | { 16 | base.Init(loopHandle.LibUv, loopHandle.LibUv.ShutdownReqSize, loopHandle.LoopRunThreadId); 17 | } 18 | 19 | public void ShutDown(UvStreamHandle uvStreamHandle, Action callBack, object state) 20 | { 21 | 22 | _callBack = callBack; 23 | _state = state; 24 | Alloc(); 25 | try 26 | { 27 | LibUv.ShutDown(this, uvStreamHandle, _ShutDown_Callback); 28 | } 29 | catch (Exception ex) 30 | { 31 | DoDispose(); 32 | throw ex; 33 | } 34 | } 35 | 36 | private static void ShutDown_Callback(IntPtr intPtr, int arg) 37 | { 38 | ShutdownHandle shutdownHandle = GetObjectFromHandel(intPtr); 39 | if (shutdownHandle == null || shutdownHandle._callBack == null) 40 | { 41 | return; 42 | } 43 | try 44 | { 45 | shutdownHandle._callBack(arg, shutdownHandle._state); 46 | } 47 | catch 48 | { 49 | //ignore 50 | } 51 | shutdownHandle.DoDispose(); 52 | shutdownHandle.Dispose(); 53 | shutdownHandle._callBack = null; 54 | shutdownHandle._state = null; 55 | } 56 | 57 | protected override bool ReleaseHandle() 58 | { 59 | _Close_Callback(handle); 60 | handle = IntPtr.Zero; 61 | return true; 62 | } 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Demo/WebSocket.Demo2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WebSocket Test 7 | 8 | 9 | 44 | 45 | 46 | 47 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |


你输入什么,服务器就回复什么,试试!!
60 | 61 |
62 |
63 |

64 |
65 |
66 |
67 |
68 | 69 |
70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /OwinDog/Service/RequestCheck.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | 4 | namespace Service 5 | { 6 | 7 | public static class RequestCheck 8 | { 9 | private static string[] NotSafeArray = new string[] 10 | { 11 | "/bin", 12 | "/views", 13 | "/app_code", 14 | "/app_data" 15 | }; 16 | 17 | private static readonly ConcurrentDictionary SafeRequestUrlDic = new ConcurrentDictionary(); 18 | 19 | /// 20 | /// 测试非法地址 21 | /// 22 | /// 23 | /// 24 | public static bool IsNotSafeRequest(string url) 25 | { 26 | if (string.IsNullOrEmpty(url)) 27 | { 28 | return false; 29 | } 30 | bool flag = false; 31 | if (SafeRequestUrlDic.TryGetValue(url, out flag)) 32 | { 33 | return flag; 34 | } 35 | flag = true; 36 | int num = url.IndexOf('/', 1); 37 | if (num < 3) 38 | { 39 | return true; 40 | } 41 | string path = url.Substring(0, num); 42 | for (int i = 0; i < NotSafeArray.Length; i++) 43 | { 44 | string item = NotSafeArray[i]; 45 | if (string.Equals(path, item, StringComparison.OrdinalIgnoreCase)) 46 | { 47 | flag = false; 48 | break; 49 | } 50 | } 51 | if (flag && url.IndexOf("/.") != -1) 52 | { 53 | flag = false; 54 | } 55 | if (flag && url.EndsWith(".config", StringComparison.OrdinalIgnoreCase)) 56 | { 57 | flag = false; 58 | } 59 | if (flag && url.EndsWith(".asax", StringComparison.OrdinalIgnoreCase)) 60 | { 61 | flag = false; 62 | } 63 | SafeRequestUrlDic[url] = flag; 64 | return flag; 65 | } 66 | 67 | /// 68 | /// 排除 69 | /// 70 | /// 71 | public static void Expect(string key) 72 | { 73 | SafeRequestUrlDic[key] = false; 74 | } 75 | 76 | 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /OwinDog/Service/ApplicationInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Reflection; 5 | using System.Runtime.CompilerServices; 6 | using System.Threading; 7 | using Util; 8 | using OwinEngine; 9 | 10 | namespace Service 11 | { 12 | public static class ApplicationInfo 13 | { 14 | public const string ServerInfo = "OwinDog/1.0"; 15 | 16 | public static readonly string Version = Assembly.GetExecutingAssembly().GetName().Version.ToString(); 17 | 18 | public static string AppPtah { get; set; } 19 | 20 | /// 21 | /// 默认是 owindog.exe 所在的 site\wwwroot 目录 放置网站运行程序的 22 | /// 23 | public static string Wwwroot { get; set; } 24 | 25 | public static string Approot { get; set; } 26 | 27 | public static OwinAdapter OwinAdapter { get; set; } 28 | 29 | 30 | public static void SetApplicationPath(string appPath, string rootPath) 31 | { 32 | // -root 网站或webapi的物理路径,如 owindog -root d:\myapi\wwwroot。 33 | //(不加该参数时,默认路径是owindog.exe所在文件夹内的site\wwwroot目录) 34 | AppPtah = (appPath); 35 | bool isWindows = SystemUtil.IsWindowOs(); 36 | if (string.IsNullOrEmpty(rootPath)) 37 | { 38 | Wwwroot = (Path.Combine(appPath, "site", "wwwroot")); 39 | Approot = (Path.Combine(appPath, "site", "approot")); 40 | return; 41 | } 42 | if ((!isWindows && rootPath[0] != '/') || (isWindows && rootPath.Length > 1 && rootPath[1] != ':')) 43 | { 44 | string root = Path.Combine(AppPtah, rootPath); 45 | root = Path.GetFullPath(root); 46 | Wwwroot = (root); 47 | DirectoryInfo directoryInfo = new DirectoryInfo(Wwwroot); 48 | string fullName = directoryInfo.Parent.FullName; 49 | root = Path.Combine(fullName, "approot"); 50 | if (Directory.Exists(root)) 51 | { 52 | Approot = (root); 53 | } 54 | } 55 | else 56 | { 57 | Wwwroot = rootPath; 58 | string fullName; 59 | try 60 | { 61 | fullName = new DirectoryInfo(rootPath).Parent.FullName; 62 | } 63 | catch 64 | { 65 | throw new IOException(string.Format("Error. Path: {0}", rootPath)); 66 | } 67 | 68 | string root = Path.Combine(fullName, "approot"); 69 | if (Directory.Exists(root)) 70 | { 71 | Approot = root; 72 | } 73 | } 74 | } 75 | 76 | 77 | 78 | } 79 | 80 | 81 | 82 | } 83 | 84 | -------------------------------------------------------------------------------- /Demo/WebSocket.Demo2/WebSocket.Demo2.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {DA9B5E13-8607-4E44-8350-74A011D5D07A} 8 | Library 9 | Properties 10 | WebSocket.Demo2 11 | WebSocket.Demo2 12 | v4.5 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 62 | -------------------------------------------------------------------------------- /Owin.WebSocket/Handlers/NetWebSocket.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.WebSockets; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using Owin.WebSocket.Extensions; 6 | 7 | namespace Owin.WebSocket.Handlers 8 | { 9 | class NetWebSocket: IWebSocket 10 | { 11 | private readonly TaskQueue mSendQueue; 12 | private readonly System.Net.WebSockets.WebSocket mWebSocket; 13 | 14 | public NetWebSocket(System.Net.WebSockets.WebSocket webSocket) 15 | { 16 | mWebSocket = webSocket; 17 | mSendQueue = new TaskQueue(); 18 | } 19 | 20 | public TaskQueue SendQueue 21 | { 22 | get { return mSendQueue; } 23 | } 24 | 25 | public WebSocketCloseStatus? CloseStatus 26 | { 27 | get { return mWebSocket.CloseStatus; } 28 | } 29 | 30 | public string CloseStatusDescription 31 | { 32 | get { return mWebSocket.CloseStatusDescription; } 33 | } 34 | 35 | public Task SendText(ArraySegment data, bool endOfMessage, CancellationToken cancelToken) 36 | { 37 | return Send(data, WebSocketMessageType.Text, endOfMessage, cancelToken); 38 | } 39 | 40 | public Task SendBinary(ArraySegment data, bool endOfMessage, CancellationToken cancelToken) 41 | { 42 | return Send(data, WebSocketMessageType.Binary, endOfMessage, cancelToken); 43 | } 44 | 45 | public Task Send(ArraySegment data, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancelToken) 46 | { 47 | var sendContext = new SendContext(data, endOfMessage, messageType, cancelToken); 48 | 49 | return mSendQueue.Enqueue( 50 | async s => 51 | { 52 | await mWebSocket.SendAsync(s.Buffer, s.Type, s.EndOfMessage, s.CancelToken); 53 | }, 54 | sendContext); 55 | } 56 | 57 | public Task Close(WebSocketCloseStatus closeStatus, string closeDescription, CancellationToken cancelToken) 58 | { 59 | return mWebSocket.CloseAsync(closeStatus, closeDescription, cancelToken); 60 | } 61 | 62 | public async Task, WebSocketMessageType>> ReceiveMessage(byte[] buffer, CancellationToken cancelToken) 63 | { 64 | var count = 0; 65 | WebSocketReceiveResult result; 66 | do 67 | { 68 | var segment = new ArraySegment(buffer, count, buffer.Length - count); 69 | result = await mWebSocket.ReceiveAsync(segment, cancelToken); 70 | 71 | count += result.Count; 72 | } 73 | while (!result.EndOfMessage); 74 | 75 | return new Tuple, WebSocketMessageType>(new ArraySegment(buffer, 0, count), result.MessageType); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Dog/Dog.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {3B51C35F-EF88-493A-8183-4CFECA20F263} 8 | Exe 9 | Properties 10 | Dog 11 | Dog 12 | v4.5 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | {38fd2383-56a2-408d-8cbf-1e175f8d6488} 54 | OwinDog 55 | 56 | 57 | 58 | 65 | -------------------------------------------------------------------------------- /Owin.AspEngine/AspEngine/AspRequestBroker.cs: -------------------------------------------------------------------------------- 1 | namespace Owin.AspEngine 2 | { 3 | using System; 4 | using System.Runtime.CompilerServices; 5 | 6 | internal class AspRequestBroker : MarshalByRefObject 7 | { 8 | private DelegateDomainUnload _domainUnlocad; 9 | private DelegateRead _read; 10 | private DelegateRequestEnd _requestEnd; 11 | private DelegateWrite _write; 12 | private DelegateWriteHeader _writeHeader; 13 | private DelegateWriteHttpStatus _writeStatus; 14 | 15 | public AspRequestBroker(DelegateRead read, DelegateWrite write, DelegateWriteHeader writeHeader, DelegateWriteHttpStatus writeStatus, DelegateRequestEnd reqEnd, DelegateDomainUnload domainUnload) 16 | { 17 | this._read = read; 18 | this._write = write; 19 | this._writeHeader = writeHeader; 20 | this._writeStatus = writeStatus; 21 | this._requestEnd = reqEnd; 22 | this._domainUnlocad = domainUnload; 23 | } 24 | 25 | public void DomainUnload() 26 | { 27 | this._domainUnlocad(); 28 | } 29 | 30 | public override object InitializeLifetimeService() => 31 | null; 32 | 33 | public int Read(int id, byte[] buffer, int offset, int size) => 34 | this._read(id, buffer, offset, size); 35 | 36 | public void RequestEnd(int id, bool keep) 37 | { 38 | this._requestEnd(id, keep); 39 | } 40 | 41 | public void Write(int id, byte[] buffer, int offset, int size) 42 | { 43 | this._write(id, buffer, offset, size); 44 | } 45 | 46 | public void WriteHeader(int id, string name, string value) 47 | { 48 | try 49 | { 50 | this._writeHeader(id, name, value); 51 | } 52 | catch (Exception exception) 53 | { 54 | Console.WriteLine("**** writeHandler: {0}", exception); 55 | throw; 56 | } 57 | } 58 | 59 | public void WriteStatus(int id, int statusCode, string statusDescription) 60 | { 61 | try 62 | { 63 | this._writeStatus(id, statusCode, statusDescription); 64 | } 65 | catch 66 | { 67 | Console.WriteLine("*** write status"); 68 | throw; 69 | } 70 | } 71 | 72 | public delegate void DelegateDomainUnload(); 73 | 74 | public delegate int DelegateRead(int id, byte[] buffer, int offset, int size); 75 | 76 | public delegate void DelegateRequestEnd(int id, bool keep); 77 | 78 | public delegate void DelegateWrite(int id, byte[] buffer, int offset, int size); 79 | 80 | public delegate void DelegateWriteHeader(int id, string name, string value); 81 | 82 | public delegate void DelegateWriteHttpStatus(int id, int statusCode, string statusDescription); 83 | } 84 | } 85 | 86 | -------------------------------------------------------------------------------- /Demo/AspTest/AspTest.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {83C619A2-4AE4-4029-945B-657F7159396E} 8 | Library 9 | Properties 10 | AspTest 11 | AspTest 12 | v4.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | Default.aspx 46 | 47 | 48 | 49 | 50 | 51 | {e044c158-1347-4a46-bb69-fe7403d2eb0e} 52 | Owin.AspEngine 53 | 54 | 55 | 56 | 57 | 58 | 59 | 66 | -------------------------------------------------------------------------------- /Owin.AspEngine/Owin.AspEngine.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {E044C158-1347-4A46-BB69-FE7403D2EB0E} 8 | Library 9 | Properties 10 | Owin.AspEngine 11 | Owin.AspEngine 12 | v4.5 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | true 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 66 | -------------------------------------------------------------------------------- /Owin.WebSocket/Extensions/OwinExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Collections.Generic; 4 | using System.Text.RegularExpressions; 5 | using Microsoft.Practices.ServiceLocation; 6 | 7 | namespace Owin.WebSocket.Extensions 8 | { 9 | /// 10 | /// https://github.com/bryceg/Owin.WebSocket 11 | /// 12 | public static class OwinExtension 13 | { 14 | /// 15 | /// Maps a static URI to a web socket consumer 16 | /// 17 | /// Type of WebSocketHubConnection 18 | /// Owin App 19 | /// Static URI to map to the hub 20 | /// Service locator to use for getting instances of T 21 | public static void MapWebSocketRoute(this IAppBuilder app, string route, IServiceLocator serviceLocator = null) 22 | where T : WebSocketConnection 23 | { 24 | app.Map(route, config => config.Use>(serviceLocator)); 25 | } 26 | 27 | /// 28 | /// Maps a URI pattern to a web socket consumer using a Regex pattern mach on the URI 29 | /// 30 | /// Type of WebSocketHubConnection 31 | /// Owin app /// 32 | /// Regex pattern of the URI to match. Capture groups will be sent to the hub on the Arguments property 33 | /// Service locator to use for getting instances of T 34 | public static void MapWebSocketPattern(this IAppBuilder app, string regexPatternMatch, IServiceLocator serviceLocator = null) 35 | where T : WebSocketConnection 36 | { 37 | app.Use>(serviceLocator, new Regex(regexPatternMatch, RegexOptions.Compiled | RegexOptions.IgnoreCase)); 38 | } 39 | 40 | /// 41 | /// Maps a static URI route to the web socket connection using the WebSocketRouteAttribute 42 | /// 43 | /// Type of WebSocketHubConnection 44 | /// Owin App 45 | /// Service locator to use for getting instances of T 46 | public static void MapWebSocketRoute(this IAppBuilder app, IServiceLocator serviceLocator = null) 47 | where T : WebSocketConnection 48 | { 49 | var routeAttributes = typeof(T).GetCustomAttributes(typeof(WebSocketRouteAttribute), true); 50 | 51 | if (routeAttributes.Length == 0) 52 | throw new InvalidOperationException(typeof(T).Name + " type must have attribute of WebSocketRouteAttribute for mapping"); 53 | 54 | foreach (var routeAttribute in routeAttributes.Cast()) 55 | { 56 | app.Map(routeAttribute.Route, config => config.Use>(serviceLocator)); 57 | } 58 | } 59 | 60 | internal static T Get(this IDictionary dictionary, string key) 61 | { 62 | object item; 63 | if (dictionary.TryGetValue(key, out item)) 64 | { 65 | return (T) item; 66 | } 67 | 68 | return default(T); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Owin.AspEngine/AspEngine/AspApplicationHost.cs: -------------------------------------------------------------------------------- 1 | namespace Owin.AspEngine 2 | { 3 | using System; 4 | using System.Reflection; 5 | using System.Runtime.CompilerServices; 6 | using System.Text; 7 | using System.Web; 8 | using System.Web.Configuration; 9 | 10 | internal sealed class AspApplicationHost : MarshalByRefObject 11 | { 12 | private string _mPath; 13 | private volatile bool _mUnloading; 14 | private string _mVPath; 15 | private AspRequestBroker _requestBroker; 16 | 17 | 18 | public AspApplicationHost() 19 | { 20 | AppDomain.CurrentDomain.DomainUnload += new EventHandler(this.OnHostDomainUnload); 21 | try 22 | { 23 | this.WebConfigResponseEncoding = this.GetResponseEncodingFromWebConfig(); 24 | } 25 | catch 26 | { 27 | this.WebConfigResponseEncoding = Encoding.UTF8; 28 | } 29 | } 30 | 31 | private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) => 32 | null; 33 | 34 | /// 35 | /// 从Web.config中的配置节点读取ResponseEncoding 36 | /// 37 | /// 38 | private Encoding GetResponseEncodingFromWebConfig() 39 | { 40 | try 41 | { 42 | GlobalizationSection section = WebConfigurationManager.GetSection("system.web/globalization") as GlobalizationSection; 43 | return ((section == null) ? Encoding.UTF8 : section.ResponseEncoding); 44 | } 45 | catch 46 | { 47 | return Encoding.UTF8; 48 | } 49 | } 50 | 51 | public override object InitializeLifetimeService() => 52 | null; 53 | 54 | /// 55 | /// 要求应用程序域退出时 56 | /// 57 | /// 58 | /// 59 | private void OnHostDomainUnload(object o, EventArgs args) 60 | { 61 | try 62 | { 63 | this._mUnloading = true; 64 | this._requestBroker.DomainUnload(); 65 | } 66 | catch 67 | { 68 | } 69 | } 70 | 71 | public void Process(AspRequestData req) 72 | { 73 | new AspRequestWorker().ProcessRequest(req); 74 | } 75 | 76 | public void SetRequestBroker(AspRequestBroker broker) 77 | { 78 | this._requestBroker = broker; 79 | AspRequestWorker.Init(this, broker); 80 | } 81 | 82 | public void UnLoadAppDomain() 83 | { 84 | try 85 | { 86 | this._mUnloading = true; 87 | HttpRuntime.UnloadAppDomain(); 88 | } 89 | catch 90 | { 91 | } 92 | } 93 | 94 | internal AppDomain Domain => 95 | AppDomain.CurrentDomain; 96 | 97 | public string Path => 98 | (this._mPath ?? (this._mPath = AppDomain.CurrentDomain.GetData(".appPath").ToString())); 99 | 100 | public string VPath => 101 | (this._mVPath ?? (this._mVPath = AppDomain.CurrentDomain.GetData(".appVPath").ToString())); 102 | 103 | public Encoding WebConfigResponseEncoding { get; private set; } 104 | } 105 | } 106 | 107 | -------------------------------------------------------------------------------- /Demo/Nancy.Demo2/Adapter.cs: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * 相对完整的,能支持cshtml文件的nancy应用示例 3 | * ------------------------------------------------------------------------------- 4 | * 要点:1,了解如何为AppBuilder添加参数,构造出一个比较完善的适应性强的适配器; 5 | * 2,一个比较完整的可以使用 Razor 开发网站的NancyFx环境的各种必要的配置; 6 | *************************************************************************************/ 7 | 8 | 9 | 10 | #region 11 | 12 | using System; 13 | using System.Collections.Generic; 14 | using Microsoft.Owin.Builder; 15 | using System.Threading; 16 | using System.Threading.Tasks; 17 | 18 | #endregion 19 | 20 | 21 | 22 | namespace Nancy.Demo2 23 | { 24 | 25 | /// 26 | /// owin/owindog OWIN适配器 27 | /// 28 | class Adapter 29 | { 30 | 31 | 32 | /************************************* 33 | * 这是一个比较完整的适配器示例 34 | * ***********************************/ 35 | 36 | 37 | 38 | /// 39 | /// OWIN 应用程序委托 40 | /// 41 | static Func, Task> _owinApp; 42 | 43 | 44 | /// 45 | /// 适配器构造函数 46 | /// 47 | public Adapter() 48 | { 49 | 50 | //实例化一个应用程序生成器 51 | var builder = new AppBuilder(); 52 | 53 | 54 | 55 | // 为生成器添加一些参数 56 | // 因某些OWIN框架需要从该参数中得到一些初始化环境信息 57 | // 这些信息可以包括 如“owin版本”“服务器功”能等等 58 | var properties = builder.Properties; 59 | properties["owin.Version"] = "1.0"; // 只能是1.0 60 | 61 | var disposeSource = new CancellationTokenSource(); 62 | properties["server.OnDispose"] = disposeSource.Token; 63 | 64 | Func svrInitCallback = null; 65 | Action> init = (callback) => { svrInitCallback = callback; }; 66 | properties["server.OnInit"] = init; 67 | //....... 68 | 69 | var capabilities = properties.ContainsKey("server.Capabilities") ? properties["server.Capabilities"] as IDictionary : new Dictionary(); 70 | properties["server.Capabilities"] = capabilities; 71 | capabilities["server.Name"] = "owindog"; 72 | //capabilities["websocket.Version"] = "1.0"; 73 | //...... 74 | 75 | 76 | 77 | //实例化用户的启动类,并调用配置方法 78 | //如果用户启动类在其它的dll中,就需要通过反射找出这个类 79 | var startup = new Startup(); 80 | startup.Configuration(builder); 81 | 82 | //构建OWIN应用并获取该应用的代理(委托)方法 83 | _owinApp = builder.Build(); 84 | 85 | 86 | //要求应用程序域退出时,向本类发出通知 87 | AppDomain.CurrentDomain.DomainUnload += ((o, e) => { disposeSource.Cancel(); }); 88 | 89 | //回调应用层初始化函数 90 | if (svrInitCallback != null) svrInitCallback().Wait(); 91 | 92 | } 93 | 94 | 95 | 96 | 97 | /// 98 | /// *** owin/owindog所需要的关键函数 *** 99 | /// 100 | /// 新请求的环境字典,具体内容参见OWIN标准 101 | /// 返回一个正在运行或已经完成的任务 102 | public Task OwinMain(IDictionary env) 103 | { 104 | return _owinApp == null ? null : _owinApp(env); 105 | } 106 | 107 | 108 | } //end class 109 | 110 | 111 | } //end namespace 112 | -------------------------------------------------------------------------------- /OwinDog/Util/HttpCodeUtil.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Runtime.CompilerServices; 4 | using System.Threading; 5 | 6 | namespace Util 7 | { 8 | 9 | public static class HttpCodeUtil 10 | { 11 | public static string Get(int key) 12 | { 13 | string result; 14 | if (!_dictDescription.TryGetValue(key, out result)) 15 | { 16 | result = "OK"; 17 | } 18 | return result; 19 | } 20 | 21 | private static readonly IDictionary _dictDescription = new Dictionary 22 | { 23 | { 24 | 100, 25 | "Continue" 26 | }, 27 | { 28 | 101, 29 | "Witching Protocols" 30 | }, 31 | { 32 | 102, 33 | "Processing" 34 | }, 35 | { 36 | 200, 37 | "OK" 38 | }, 39 | { 40 | 201, 41 | "Created" 42 | }, 43 | { 44 | 202, 45 | "Accepted" 46 | }, 47 | { 48 | 203, 49 | "Non-Authoritative Information" 50 | }, 51 | { 52 | 204, 53 | "No Content" 54 | }, 55 | { 56 | 205, 57 | "Reset Content" 58 | }, 59 | { 60 | 206, 61 | "Partial Content" 62 | }, 63 | { 64 | 207, 65 | "Multi-Status" 66 | }, 67 | { 68 | 300, 69 | "Multiple Choices" 70 | }, 71 | { 72 | 301, 73 | "Moved Permanently" 74 | }, 75 | { 76 | 302, 77 | "Found" 78 | }, 79 | { 80 | 303, 81 | "See Other" 82 | }, 83 | { 84 | 304, 85 | "Not Modified" 86 | }, 87 | { 88 | 305, 89 | "Use Proxy" 90 | }, 91 | { 92 | 306, 93 | "Switch Proxy" 94 | }, 95 | { 96 | 307, 97 | "Temporary Redirect" 98 | }, 99 | { 100 | 400, 101 | "Bad Request" 102 | }, 103 | { 104 | 401, 105 | "Unauthorized" 106 | }, 107 | { 108 | 402, 109 | "Payment Required" 110 | }, 111 | { 112 | 403, 113 | "Forbidden" 114 | }, 115 | { 116 | 404, 117 | "Not Found" 118 | }, 119 | { 120 | 405, 121 | "Method Not Allowed" 122 | }, 123 | { 124 | 406, 125 | "Not Acceptable" 126 | }, 127 | { 128 | 407, 129 | "Proxy Authentication Required" 130 | }, 131 | { 132 | 408, 133 | "Request Time-Out" 134 | }, 135 | { 136 | 409, 137 | "Conflict" 138 | }, 139 | { 140 | 410, 141 | "Gone" 142 | }, 143 | { 144 | 411, 145 | "Length Required" 146 | }, 147 | { 148 | 412, 149 | "Precondition Failed" 150 | }, 151 | { 152 | 413, 153 | "Request Entity Too Large" 154 | }, 155 | { 156 | 414, 157 | "Request-URI Too Large" 158 | }, 159 | { 160 | 415, 161 | "Unsupported Media Type" 162 | }, 163 | { 164 | 416, 165 | "Requested range not satisfiable" 166 | }, 167 | { 168 | 417, 169 | "Expectation Failed" 170 | }, 171 | { 172 | 500, 173 | "Internal Server Error" 174 | }, 175 | { 176 | 501, 177 | "Not Implemented" 178 | }, 179 | { 180 | 502, 181 | "Bad Gateway" 182 | }, 183 | { 184 | 503, 185 | "Service Unavailable" 186 | }, 187 | { 188 | 504, 189 | "Gateway Time-out" 190 | }, 191 | { 192 | 505, 193 | "HTTP Version not supported" 194 | }, 195 | { 196 | 506, 197 | "Variant Also Negotiates" 198 | }, 199 | { 200 | 509, 201 | "Bandwidth Limit Exceeded" 202 | } 203 | }; 204 | } 205 | 206 | 207 | 208 | 209 | 210 | } 211 | -------------------------------------------------------------------------------- /Owin.WebSocket/Extensions/TaskQueue.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace Owin.WebSocket.Extensions 6 | { 7 | // Allows serial queuing of Task instances 8 | // The tasks are not called on the current synchronization context 9 | public sealed class TaskQueue 10 | { 11 | private readonly object mLockObj = new object(); 12 | private Task mLastQueuedTask; 13 | private volatile bool mDrained; 14 | private int? mMaxSize; 15 | private int mSize; 16 | 17 | /// 18 | /// Current size of the queue depth 19 | /// 20 | public int Size { get { return mSize; } } 21 | 22 | /// 23 | /// Maximum size of the queue depth. Null = unlimited 24 | /// 25 | public int? MaxSize { get { return mMaxSize; } } 26 | 27 | public TaskQueue() 28 | : this(TaskAsyncHelper.Empty) 29 | { 30 | } 31 | 32 | public TaskQueue(Task initialTask) 33 | { 34 | mLastQueuedTask = initialTask; 35 | } 36 | 37 | /// 38 | /// Set the maximum size of the Task Queue chained operations. 39 | /// When pending send operations limits reached a null Task will be returned from Enqueue 40 | /// 41 | /// Maximum size of the queue 42 | public void SetMaxQueueSize(int? maxSize) 43 | { 44 | mMaxSize = maxSize; 45 | } 46 | 47 | /// 48 | /// Enqueue a new task on the end of the queue 49 | /// 50 | /// The enqueued Task or NULL if the max size of the queue was reached 51 | public Task Enqueue(Func taskFunc, T state) 52 | { 53 | // Lock the object for as short amount of time as possible 54 | lock (mLockObj) 55 | { 56 | if (mDrained) 57 | { 58 | return mLastQueuedTask; 59 | } 60 | 61 | Interlocked.Increment(ref mSize); 62 | 63 | if (mMaxSize != null) 64 | { 65 | // Increment the size if the queue 66 | if (mSize > mMaxSize) 67 | { 68 | Interlocked.Decrement(ref mSize); 69 | 70 | // We failed to enqueue because the size limit was reached 71 | return null; 72 | } 73 | } 74 | 75 | var newTask = mLastQueuedTask.Then((next, nextState) => 76 | { 77 | return next(nextState).Finally(s => 78 | { 79 | var queue = (TaskQueue)s; 80 | Interlocked.Decrement(ref queue.mSize); 81 | }, 82 | this); 83 | }, 84 | taskFunc, state); 85 | 86 | mLastQueuedTask = newTask; 87 | return newTask; 88 | } 89 | } 90 | 91 | /// 92 | /// Triggers a drain fo the task queue and blocks until the drain completes 93 | /// 94 | public void Drain() 95 | { 96 | lock (mLockObj) 97 | { 98 | mDrained = true; 99 | 100 | mLastQueuedTask.Wait(); 101 | 102 | mDrained = false; 103 | } 104 | } 105 | } 106 | } -------------------------------------------------------------------------------- /OwinDog/Service/ActionQueue.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.CompilerServices; 5 | using System.Threading; 6 | using Util; 7 | 8 | namespace Service 9 | { 10 | /// 11 | /// 每隔指定时间 执行所包含的Action 12 | /// 13 | public static class ActionQueue 14 | { 15 | 16 | private static bool _flag; 17 | 18 | private static readonly List _actionParamList; 19 | 20 | public static DateTime Time { get; set; } 21 | 22 | public static long LongTimes { get; set; } 23 | 24 | static ActionQueue() 25 | { 26 | _flag = false; 27 | _actionParamList = new List(); 28 | initDateTimeAndLong(); 29 | new Thread(new ThreadStart(Init)) 30 | { 31 | IsBackground = true 32 | }.Start(); 33 | } 34 | 35 | private static void ExcuteActionParam(object obj) 36 | { 37 | ActionParam actionParam = obj as ActionParam; 38 | try 39 | { 40 | if (actionParam != null) actionParam.Excute(); 41 | } 42 | catch 43 | { 44 | //ignore 45 | } 46 | finally 47 | { 48 | if (actionParam != null) actionParam.IsBreak = false; 49 | } 50 | } 51 | 52 | public static void AddAction(Action action, int times) 53 | { 54 | lock (_actionParamList) 55 | { 56 | ActionParam item = new ActionParam 57 | { 58 | Excute = action, 59 | times = times, 60 | longTimes = CommonUtil.CurrentTimes() 61 | }; 62 | _actionParamList.Add(item); 63 | } 64 | } 65 | 66 | private static void Init() 67 | { 68 | while (!_flag) 69 | { 70 | initDateTimeAndLong(); 71 | Run(); 72 | Thread.Sleep(200); 73 | } 74 | _flag = true; 75 | } 76 | 77 | private static void initDateTimeAndLong() 78 | { 79 | Time= DateTime.Now; 80 | LongTimes = CommonUtil.CurrentTimes();//从1970/01/01 00:00:01 到现在经过的毫秒数了 81 | } 82 | private static void Run() 83 | { 84 | if (_actionParamList == null || _actionParamList.Count < 1) 85 | { 86 | return; 87 | } 88 | long num = CommonUtil.CurrentTimes();//当前毫秒数 89 | lock (_actionParamList) 90 | { 91 | foreach (ActionParam current in _actionParamList) 92 | { 93 | if (checked(num - current.times) >= (long)current.longTimes && !current.IsBreak) 94 | { 95 | current.longTimes = num; 96 | current.IsBreak = true; 97 | if (!ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(ExcuteActionParam), current)) 98 | { 99 | current.IsBreak = false; 100 | } 101 | } 102 | } 103 | } 104 | } 105 | 106 | 107 | private class ActionParam 108 | { 109 | public Action Excute; 110 | 111 | public int times; 112 | 113 | public long longTimes; 114 | 115 | public bool IsBreak; 116 | } 117 | } 118 | } 119 | 120 | -------------------------------------------------------------------------------- /Owin.WebSocket/Owin.WebSocket.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {ED2EE07F-39CA-4F87-9346-E47ED3B5F4E0} 8 | Library 9 | Properties 10 | Owin.WebSocket 11 | Owin.WebSocket 12 | v4.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | ..\packages\Microsoft.Owin.3.1.0\lib\net45\Microsoft.Owin.dll 35 | True 36 | 37 | 38 | ..\packages\CommonServiceLocator.1.3\lib\portable-net4+sl5+netcore45+wpa81+wp8\Microsoft.Practices.ServiceLocation.dll 39 | True 40 | 41 | 42 | ..\packages\Owin.1.0\lib\net40\Owin.dll 43 | True 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 78 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | .svn/ 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studo 2015 cache/options directory 26 | .vs/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | # NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | # DNX 42 | project.lock.json 43 | artifacts/ 44 | 45 | *_i.c 46 | *_p.c 47 | *_i.h 48 | *.ilk 49 | *.meta 50 | *.obj 51 | *.pch 52 | *.pdb 53 | *.pgc 54 | *.pgd 55 | *.rsp 56 | *.sbr 57 | *.tlb 58 | *.tli 59 | *.tlh 60 | *.tmp 61 | *.tmp_proj 62 | *.log 63 | *.vspscc 64 | *.vssscc 65 | .builds 66 | *.pidb 67 | *.svclog 68 | *.scc 69 | 70 | # Chutzpah Test files 71 | _Chutzpah* 72 | 73 | # Visual C++ cache files 74 | ipch/ 75 | *.aps 76 | *.ncb 77 | *.opensdf 78 | *.sdf 79 | *.cachefile 80 | 81 | # Visual Studio profiler 82 | *.psess 83 | *.vsp 84 | *.vspx 85 | 86 | # TFS 2012 Local Workspace 87 | $tf/ 88 | 89 | # Guidance Automation Toolkit 90 | *.gpState 91 | 92 | # ReSharper is a .NET coding add-in 93 | _ReSharper*/ 94 | *.[Rr]e[Ss]harper 95 | *.DotSettings.user 96 | 97 | # JustCode is a .NET coding add-in 98 | .JustCode 99 | 100 | # TeamCity is a build add-in 101 | _TeamCity* 102 | 103 | # DotCover is a Code Coverage Tool 104 | *.dotCover 105 | 106 | # NCrunch 107 | _NCrunch_* 108 | .*crunch*.local.xml 109 | 110 | # MightyMoose 111 | *.mm.* 112 | AutoTest.Net/ 113 | 114 | # Web workbench (sass) 115 | .sass-cache/ 116 | 117 | # Installshield output folder 118 | [Ee]xpress/ 119 | 120 | # DocProject is a documentation generator add-in 121 | DocProject/buildhelp/ 122 | DocProject/Help/*.HxT 123 | DocProject/Help/*.HxC 124 | DocProject/Help/*.hhc 125 | DocProject/Help/*.hhk 126 | DocProject/Help/*.hhp 127 | DocProject/Help/Html2 128 | DocProject/Help/html 129 | 130 | # Click-Once directory 131 | publish/ 132 | 133 | # Publish Web Output 134 | *.[Pp]ublish.xml 135 | *.azurePubxml 136 | # TODO: Comment the next line if you want to checkin your web deploy settings 137 | # but database connection strings (with potential passwords) will be unencrypted 138 | *.pubxml 139 | *.publishproj 140 | 141 | # NuGet Packages 142 | *.nupkg 143 | # The packages folder can be ignored because of Package Restore 144 | **/packages/* 145 | # except build/, which is used as an MSBuild target. 146 | !**/packages/build/ 147 | # Uncomment if necessary however generally it will be regenerated when needed 148 | #!**/packages/repositories.config 149 | 150 | # Windows Azure Build Output 151 | csx/ 152 | *.build.csdef 153 | 154 | # Windows Store app package directory 155 | AppPackages/ 156 | 157 | # Visual Studio cache files 158 | # files ending in .cache can be ignored 159 | *.[Cc]ache 160 | # but keep track of directories ending in .cache 161 | !*.[Cc]ache/ 162 | 163 | # Others 164 | ClientBin/ 165 | [Ss]tyle[Cc]op.* 166 | ~$* 167 | *~ 168 | *.dbmdl 169 | *.dbproj.schemaview 170 | *.pfx 171 | *.publishsettings 172 | node_modules/ 173 | bower_components/ 174 | orleans.codegen.cs 175 | 176 | # RIA/Silverlight projects 177 | Generated_Code/ 178 | 179 | # Backup & report files from converting an old project file 180 | # to a newer Visual Studio version. Backup files are not needed, 181 | # because we have git ;-) 182 | _UpgradeReport_Files/ 183 | Backup*/ 184 | UpgradeLog*.XML 185 | UpgradeLog*.htm 186 | 187 | # SQL Server files 188 | *.mdf 189 | *.ldf 190 | 191 | # Business Intelligence projects 192 | *.rdl.data 193 | *.bim.layout 194 | *.bim_*.settings 195 | 196 | # Microsoft Fakes 197 | FakesAssemblies/ 198 | 199 | # Node.js Tools for Visual Studio 200 | .ntvs_analysis.dat 201 | 202 | # Visual Studio 6 build log 203 | *.plg 204 | 205 | # Visual Studio 6 workspace options file 206 | *.opt 207 | 208 | UpLoad/ 209 | driver_config.xml 210 | -------------------------------------------------------------------------------- /OwinDog/OwinEngine/HeaderDictionary.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace OwinEngine 7 | { 8 | internal class HeaderDictionary : IDictionary, ICollection>, IEnumerable>, IEnumerable 9 | { 10 | private readonly Dictionary Headers; 11 | 12 | public HeaderDictionary() 13 | { 14 | Headers = new Dictionary(StringComparer.OrdinalIgnoreCase); 15 | } 16 | 17 | public void Add(KeyValuePair item) 18 | { 19 | Headers.Add(item.Key, item.Value); 20 | } 21 | 22 | public void Add(string key, string[] value) 23 | { 24 | Headers.Add(key, value); 25 | } 26 | 27 | public void Clear() 28 | { 29 | Headers.Clear(); 30 | } 31 | 32 | public bool Contains(KeyValuePair item) 33 | { 34 | return ((ICollection>)Headers).Contains(item); 35 | } 36 | 37 | public bool ContainsKey(string key) 38 | { 39 | return Headers.ContainsKey(key); 40 | } 41 | 42 | public void CopyTo(KeyValuePair[] array, int arrayIndex) 43 | { 44 | ((ICollection>)Headers).CopyTo(array, arrayIndex); 45 | } 46 | 47 | private static string[] CreateArrayCopy(string[] original) 48 | { 49 | string[] array = new string[original.Length]; 50 | Array.Copy(original, array, original.Length); 51 | return array; 52 | } 53 | 54 | public IEnumerator> GetEnumerator() 55 | { 56 | return ((IEnumerable>)Headers).GetEnumerator(); 57 | } 58 | 59 | public bool Remove(string key) 60 | { 61 | return Headers.Remove(key); 62 | } 63 | 64 | public bool Remove(KeyValuePair item) 65 | { 66 | return ((ICollection>)Headers).Remove(item); 67 | } 68 | 69 | IEnumerator IEnumerable.GetEnumerator() 70 | { 71 | return GetEnumerator(); 72 | } 73 | 74 | public bool TryGetValue(string key, out string[] value) 75 | { 76 | string[] original; 77 | if (Headers.TryGetValue(key, out original)) 78 | { 79 | value = CreateArrayCopy(original); 80 | return true; 81 | } 82 | value = null; 83 | return false; 84 | } 85 | 86 | public int Count 87 | { 88 | get 89 | { 90 | return Headers.Count; 91 | } 92 | } 93 | 94 | public bool IsReadOnly 95 | { 96 | get 97 | { 98 | return false; 99 | } 100 | } 101 | 102 | public string[] this[string key] 103 | { 104 | get 105 | { 106 | return CreateArrayCopy(Headers[key]); 107 | } 108 | set 109 | { 110 | Headers[key] = value; 111 | } 112 | } 113 | 114 | public ICollection Keys 115 | { 116 | get 117 | { 118 | return Headers.Keys; 119 | } 120 | } 121 | 122 | public ICollection Values 123 | { 124 | get 125 | { 126 | List list = Headers.Values.ToList(); 127 | checked 128 | { 129 | for (int i = 0; i < list.Count; i++) 130 | { 131 | string[] array = list[i]; 132 | list[i] = new string[] 133 | { 134 | array[0] 135 | }; 136 | } 137 | return list; 138 | } 139 | } 140 | } 141 | 142 | 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /Demo/WebSocket.Demo2/Adapter.cs: -------------------------------------------------------------------------------- 1 | /*************************************************************** 2 | * WebSocket 应用示例 之二 3 | * ============================================================= 4 | * 本DEMO的目的意义: 5 | * 演示封装一个 WebSocket 对象 6 | * 7 | * 使用方法:将编译得到的dll放到网站的bin文件夹中。 8 | * *************************************************************/ 9 | 10 | 11 | #region 12 | 13 | using System; 14 | using System.Collections.Generic; 15 | using System.Text; 16 | using System.Threading.Tasks; 17 | using System.IO; 18 | using System.Linq; 19 | using System.Threading; 20 | 21 | #endregion 22 | 23 | 24 | namespace WebSocket.Demo 25 | { 26 | 27 | /// 28 | /// owin/owindog For OWIN 接口类 29 | /// 30 | public class Adapter 31 | { 32 | 33 | 34 | /// 35 | /// OWIN适配器的主函数 36 | /// 37 | /// 38 | /// 39 | public Task OwinMain(IDictionary env) 40 | { 41 | //是否包含Websocket握手函数并尝试进行WebSocket连接 42 | if (env.ContainsKey("websocket.Accept")) 43 | { 44 | var websocket = new WebSocket(env); 45 | 46 | //if(websocket.RequestPath == ......) 47 | 48 | if (websocket.Accept()) 49 | { 50 | 51 | websocket.OnSend = OnSend; 52 | websocket.OnClose = OnClose; 53 | websocket.OnRead = OnRead; 54 | 55 | 56 | // ..... 57 | // websocket.RemoteIpAddress 58 | // ..... 59 | // ...... 60 | 61 | //开始接受远端数据 62 | //本方法只需在连接成功后调用一次。 63 | websocket.StartRead(); 64 | 65 | //返回表示完成的任务 66 | return Task.Delay(0); 67 | } 68 | } 69 | 70 | //如果不是websocket请求,就接普通OWIN处理 71 | return ProcessRequest(env); 72 | } 73 | 74 | 75 | 76 | /// 77 | /// 数据接收事件 78 | /// 79 | /// 80 | /// 81 | void OnRead(object sender, string message) 82 | { 83 | var websocket = sender as WebSocket; 84 | 85 | if (message == "exit" || message == "close") 86 | { 87 | websocket.Close(); 88 | return; 89 | } 90 | 91 | websocket.Send(message); 92 | } 93 | 94 | 95 | /// 96 | /// 数据发送完成的事件 97 | /// 98 | /// 99 | void OnSend(object sender) 100 | { 101 | /// ..... //// 102 | } 103 | 104 | 105 | /// 106 | /// 连接已经关闭 107 | /// 108 | /// 109 | void OnClose(object sender) 110 | { 111 | // ... ... // 112 | } 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | /// 121 | /// 普通OWIN请求的处理函数 122 | /// 123 | /// 124 | /// 125 | private Task ProcessRequest(IDictionary env) 126 | { 127 | 128 | // 从字典中获取向客户(浏览器)发送数据的“流”对象 129 | ///////////////////////////////////////////////////////// 130 | var responseStream = env["owin.ResponseBody"] as Stream; 131 | 132 | // 你准备发送的数据 133 | const string outString = "Owin ServerOwin Server!

Owin Server,放飞您灵感的翅膀...

\r\n"; 134 | var outBytes = Encoding.UTF8.GetBytes(outString); 135 | 136 | // 从参数字典中获取Response HTTP头的字典对象 137 | var responseHeaders = env["owin.ResponseHeaders"] as IDictionary; 138 | 139 | // 设置必要的http响应头 140 | //////////////////////////////////////////////////////////////// 141 | 142 | // 设置 Content-Type头 143 | responseHeaders.Add("Content-Type", new[] { "text/html; charset=utf-8" }); 144 | 145 | 146 | // 把正文写入流中,发送给浏览器 147 | responseStream.Write(outBytes, 0, outBytes.Length); 148 | 149 | return Task.FromResult(0); 150 | 151 | } 152 | 153 | 154 | } 155 | 156 | 157 | 158 | } 159 | -------------------------------------------------------------------------------- /OwinDog/Util/SystemUtil.cs: -------------------------------------------------------------------------------- 1 | 2 | using Model; 3 | 4 | namespace Util 5 | { 6 | using System; 7 | using System.Runtime.InteropServices; 8 | using System.Security; 9 | 10 | public static class SystemUtil 11 | { 12 | private static unsafe string GetUname() 13 | { 14 | byte[] array = new byte[8192]; 15 | string result; 16 | try 17 | { 18 | try 19 | { 20 | fixed (byte* ptr = array) 21 | { 22 | if (uname((IntPtr)((void*)ptr)) == 0) 23 | { 24 | result = Marshal.PtrToStringAnsi((IntPtr)((void*)ptr)); 25 | return result; 26 | } 27 | } 28 | } 29 | finally 30 | { 31 | byte* ptr = null; 32 | } 33 | result = string.Empty; 34 | } 35 | catch 36 | { 37 | result = string.Empty; 38 | } 39 | return result; 40 | } 41 | 42 | public static bool IsWindowOs() 43 | { 44 | int platform = (int)Environment.OSVersion.Platform; 45 | return platform != 4 && platform != 6 && platform != 128; 46 | } 47 | 48 | public static void Init(LibUv b1) 49 | { 50 | if (b1.IsWindows) 51 | { 52 | InitLibWindows.InitLib(b1); 53 | return; 54 | } 55 | InitLibUnix.InitLib(b1); 56 | } 57 | 58 | public static bool IsDarwin() 59 | { 60 | return string.Equals(GetUname(), "Darwin", StringComparison.Ordinal); 61 | } 62 | 63 | 64 | [DllImport("libc", EntryPoint = "uname")] 65 | private static extern int uname(IntPtr entry); 66 | public static class InitLibUnix 67 | { 68 | 69 | public static void InitLib(LibUv libUv) 70 | { 71 | libUv.LoadLibrary = new Func(LoadLibrary); 72 | libUv.FreeLibrary = new Func(FreeLibrary); 73 | libUv.GetProcAddress = new Func(GetProcAddress); 74 | } 75 | 76 | public static bool FreeLibrary(IntPtr ptr1) 77 | { 78 | return (dlclose(ptr1) == 0); 79 | } 80 | 81 | public static IntPtr GetProcAddress(IntPtr ptr1, string text1) 82 | { 83 | dlerror(); 84 | IntPtr ptr = dlsym(ptr1, text1); 85 | if (!(dlerror() == IntPtr.Zero)) 86 | { 87 | return IntPtr.Zero; 88 | } 89 | return ptr; 90 | } 91 | 92 | public static IntPtr LoadLibrary(string text1) 93 | { 94 | return dlopen(text1, 2); 95 | } 96 | 97 | 98 | [SuppressUnmanagedCodeSecurity, DllImport("__Internal", EntryPoint="dlclose", SetLastError=true)] 99 | public static extern int dlclose(IntPtr aa); 100 | 101 | 102 | [SuppressUnmanagedCodeSecurity, DllImport("__Internal", EntryPoint = "dlerror", SetLastError = true)] 103 | public static extern IntPtr dlerror(); 104 | 105 | [SuppressUnmanagedCodeSecurity, DllImport("__Internal", EntryPoint="dlsym", SetLastError=true)] 106 | public static extern IntPtr dlsym(IntPtr aa, string bb); 107 | 108 | [SuppressUnmanagedCodeSecurity, DllImport("__Internal", EntryPoint="dlopen", SetLastError=true)] 109 | public static extern IntPtr dlopen([MarshalAs(UnmanagedType.LPStr)] string aa, int bb); 110 | } 111 | 112 | public static class InitLibWindows 113 | { 114 | public static void InitLib(LibUv libUv) 115 | { 116 | libUv.LoadLibrary = new Func(LoadLibrary); 117 | libUv.FreeLibrary = new Func(FreeLibrary); 118 | libUv.GetProcAddress = new Func(GetProcAddress); 119 | } 120 | 121 | [DllImport("kernel32", EntryPoint="FreeLibrary")] 122 | public static extern bool FreeLibrary(IntPtr lib); 123 | 124 | [DllImport("kernel32", EntryPoint="LoadLibrary")] 125 | public static extern IntPtr LoadLibrary(string lib); 126 | 127 | [DllImport("kernel32", EntryPoint="GetProcAddress", CharSet=CharSet.Ansi, SetLastError=true, ExactSpelling=true)] 128 | public static extern IntPtr GetProcAddress(IntPtr p, string a); 129 | } 130 | } 131 | } 132 | 133 | -------------------------------------------------------------------------------- /OwinDog/Service/ActionStoreManage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.ExceptionServices; 5 | using System.Runtime.InteropServices; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | using System.Timers; 9 | 10 | namespace Service 11 | { 12 | 13 | public static class ActionStoreManage 14 | { 15 | private static readonly ActionStore _actionStore = new ActionStore(); 16 | 17 | /// 18 | /// 添加action 19 | /// 20 | /// 21 | /// 所在的分组index 22 | public static int Add(Action action) 23 | { 24 | return _actionStore.AddAction(action, 30); 25 | } 26 | 27 | /// 28 | /// 根据所在的分组index 去删除包含的action 29 | /// 30 | /// 所在分组的index 31 | /// 32 | public static void Remove(int num, Action action) 33 | { 34 | _actionStore.RemoveAction(num, action); 35 | } 36 | 37 | /// 38 | /// 执行 39 | /// 40 | /// 41 | /// 42 | public static void Excute(object obj, ElapsedEventArgs elapsedEventArgs) 43 | { 44 | IList list = _actionStore.Get(); 45 | if (list == null || list.Count < 1) 46 | { 47 | return; 48 | } 49 | foreach (Action current in list) 50 | { 51 | current(); 52 | } 53 | } 54 | 55 | 56 | private class ActionStore 57 | { 58 | /// 59 | /// 共有120组 60 | /// 61 | private const int MaxSize = 120; 62 | 63 | /// 64 | /// 游标 65 | /// 66 | private int _index; 67 | 68 | private readonly object lockObject = new object(); 69 | 70 | private readonly List[] ActionList = new List[MaxSize]; 71 | public ActionStore() 72 | { 73 | //初始化 74 | for (int i = 0; i < ActionList.Length; i++) 75 | { 76 | ActionList[i] = new List(); 77 | } 78 | } 79 | 80 | /// 81 | /// 获取组action 然后清空该组 且 游标自增 82 | /// 83 | /// 84 | public IList Get() 85 | { 86 | 87 | IList result; 88 | lock (lockObject) 89 | { 90 | if (ActionList[_index].Count < 1) 91 | { 92 | _index = (_index + 1) % MaxSize;//这种写法的好处是自增最大不会超过MaxSize 93 | result = null; 94 | } 95 | else 96 | { 97 | //去除分组下的所有的action集合 98 | IList list = ActionList[_index]; 99 | //清空 100 | ActionList[_index] = new List(); 101 | _index = (_index + 1) % MaxSize; 102 | //返回 103 | result = list; 104 | } 105 | } 106 | return result; 107 | } 108 | 109 | /// 110 | /// 分组 添加action 111 | /// 112 | /// 113 | /// 114 | /// 115 | public int AddAction(Action item, int num) 116 | { 117 | int result; 118 | lock (lockObject) 119 | { 120 | int num2 = (_index + num) % MaxSize; 121 | ActionList[num2].Add(item); 122 | result = num2; 123 | } 124 | return result; 125 | } 126 | 127 | /// 128 | /// 移除所在分组的action 129 | /// 130 | /// 131 | /// 132 | public void RemoveAction(int num, Action item) 133 | { 134 | if (num < 0 || num >= MaxSize) 135 | { 136 | return; 137 | } 138 | lock (lockObject) 139 | { 140 | if (ActionList[num].Contains(item)) 141 | { 142 | ActionList[num].Remove(item); 143 | } 144 | } 145 | } 146 | } 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /OwinDog/Model/HandleBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Threading; 6 | 7 | namespace Model 8 | { 9 | public abstract class HandleBase : SafeHandle 10 | { 11 | protected static LibUv.Close_Callback _Close_Callback = new LibUv.Close_Callback(Free); 12 | 13 | protected Action, object> _postAsync; 14 | 15 | //帮我们在地址和对象之间进行转换 16 | private GCHandle _GCHandle; 17 | 18 | 19 | protected HandleBase() : base(IntPtr.Zero, true) 20 | { 21 | } 22 | 23 | public LibUv LibUv { get; protected set; } 24 | 25 | /// 26 | /// 跑 loopRun的 线程Id 27 | /// 28 | public int LoopRunThreadId { get; set; } 29 | 30 | 31 | 32 | 33 | #region 释放 34 | protected static unsafe void Free(IntPtr intPtr) 35 | { 36 | if (intPtr == IntPtr.Zero) 37 | { 38 | return; 39 | } 40 | FreeHandle(intPtr, *(IntPtr*)((void*)intPtr)); 41 | } 42 | protected static void FreeHandle(IntPtr intPtr, IntPtr intPtr2) 43 | { 44 | if (intPtr2 != IntPtr.Zero) 45 | { 46 | try 47 | { 48 | //返回从某个托管对象的句柄创建的新 GCHandle 对象 49 | GCHandle.FromIntPtr(intPtr2).Free(); 50 | } 51 | catch 52 | { 53 | //ignore 54 | } 55 | } 56 | if (intPtr == IntPtr.Zero) 57 | { 58 | return; 59 | } 60 | //释放由非托管 COM 任务内存分配器使用 Marshal.AllocCoTaskMem 分配的内存块 61 | Marshal.FreeCoTaskMem(intPtr); 62 | } 63 | #endregion 64 | public void Debug(bool flag = false) 65 | { 66 | if (!flag && IsClosed) 67 | { 68 | Console.WriteLine("DEBUG: OwinDog.UvHandle.Validate: Handle is closed."); 69 | } 70 | if (IsInvalid) 71 | { 72 | Console.WriteLine("DEBUG: OwinDog.UvHandle.Validate: Handle is invalid."); 73 | } 74 | } 75 | 76 | public static unsafe T GetObjectFromHandel(IntPtr value) 77 | { 78 | return (T)((object)GCHandle.FromIntPtr(*(IntPtr*)((void*)value)).Target); 79 | } 80 | 81 | 82 | 83 | protected unsafe void Init(LibUv libuv, int hdle, int point) 84 | { 85 | LibUv = libuv; 86 | LoopRunThreadId = point; 87 | //Starting with libuv v1.0, users should allocate the memory for the loops before initializing it with uv_loop_init(uv_loop_t *). This allows you to plug in custom memory management 88 | handle = Marshal.AllocCoTaskMem(hdle);//申请内存 89 | *(IntPtr*)((void*)handle) = GCHandle.ToIntPtr(GCHandle.Alloc(this, GCHandleType.Weak)); 90 | } 91 | 92 | public IntPtr InternalGetHandle() 93 | { 94 | return handle; 95 | } 96 | 97 | public virtual void Alloc() 98 | { 99 | _GCHandle = GCHandle.Alloc(this, GCHandleType.Normal); 100 | } 101 | 102 | public virtual void DoDispose() 103 | { 104 | _GCHandle.Free(); 105 | } 106 | 107 | public void UvRef() 108 | { 109 | LibUv.UvRef(this); 110 | } 111 | 112 | public void UvUnRef() 113 | { 114 | LibUv.UvUnRef(this); 115 | } 116 | 117 | public override bool IsInvalid 118 | { 119 | get 120 | { 121 | return handle == IntPtr.Zero; 122 | } 123 | } 124 | 125 | protected override bool ReleaseHandle() 126 | { 127 | IntPtr intPtr = Interlocked.Exchange(ref handle, IntPtr.Zero); 128 | if (intPtr != IntPtr.Zero) 129 | { 130 | if (Thread.CurrentThread.ManagedThreadId != LoopRunThreadId) 131 | { 132 | if (_postAsync != null) 133 | { 134 | HandleRelease handleRelease = new HandleRelease(); 135 | handleRelease.LibUv = LibUv; 136 | _postAsync(new Action(handleRelease.Release), intPtr); 137 | } 138 | } 139 | else 140 | { 141 | LibUv.UvClose(intPtr, _Close_Callback); 142 | } 143 | } 144 | return true; 145 | } 146 | 147 | 148 | 149 | private sealed class HandleRelease 150 | { 151 | public void Release(object obj) 152 | { 153 | LibUv.UvClose((IntPtr)obj, _Close_Callback); 154 | } 155 | 156 | public LibUv LibUv; 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /OwinDog/OwinEngine/OwinAdapter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Reflection; 5 | using System.Threading.Tasks; 6 | using Service; 7 | 8 | namespace OwinEngine 9 | { 10 | 11 | public class OwinAdapter 12 | { 13 | 14 | 15 | private readonly string _htmlRootBinPath; 16 | 17 | private readonly string _appRootPath; 18 | 19 | /// 20 | /// Owin入口 21 | /// 22 | public Func, Task> OwinMain { get; set; } 23 | 24 | /// 25 | /// Owin Adapter Class 26 | /// 27 | public object OwinMainClass { get; set; } 28 | 29 | 30 | 31 | public OwinAdapter() 32 | { 33 | _htmlRootBinPath = Path.Combine(ApplicationInfo.Wwwroot, "bin"); 34 | if (!Directory.Exists(_htmlRootBinPath)) 35 | { 36 | _htmlRootBinPath = Path.Combine(ApplicationInfo.Wwwroot, "Bin"); 37 | if (!Directory.Exists(_htmlRootBinPath)) 38 | { 39 | _htmlRootBinPath = ""; 40 | } 41 | } 42 | _appRootPath = ApplicationInfo.Approot; 43 | if (!Directory.Exists(_appRootPath)) 44 | { 45 | _appRootPath = ""; 46 | } 47 | } 48 | 49 | 50 | /// 51 | /// 遍历每个dll 去找到指定的class 52 | /// 53 | /// bin目录 54 | /// 55 | private bool FindFromDirectory(string libPath) 56 | { 57 | FileInfo[] files = new DirectoryInfo(libPath).GetFiles("*.dll", SearchOption.AllDirectories); 58 | if (files.Length < 1) 59 | { 60 | return false; 61 | } 62 | 63 | foreach (var fileInfo in files) 64 | { 65 | Assembly assembly = null; 66 | try 67 | { 68 | assembly = AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(fileInfo.FullName)); 69 | } 70 | catch 71 | { 72 | continue; 73 | } 74 | 75 | try 76 | { 77 | if (FindFromAssembly(assembly)) 78 | { 79 | return true; 80 | } 81 | } 82 | catch 83 | { 84 | continue; 85 | } 86 | } 87 | return false; 88 | } 89 | 90 | /// 91 | /// 从程序集里面找到 OwinMain 方法的Class 92 | /// 93 | /// 94 | /// 95 | private bool FindFromAssembly(Assembly assembly) 96 | { 97 | Type[] types = null; 98 | try 99 | { 100 | types = assembly.GetTypes(); 101 | } 102 | catch 103 | { 104 | //Console.WriteLine(e); 105 | return false; 106 | } 107 | if (types.Length < 1) 108 | { 109 | return false; 110 | } 111 | 112 | foreach (var type in types) 113 | { 114 | MethodInfo methodInfo = null; 115 | try 116 | { 117 | methodInfo = type.GetMethod("OwinMain", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); 118 | } 119 | catch 120 | { 121 | continue; 122 | } 123 | if (methodInfo == null || methodInfo.ReturnType != typeof(Task)) 124 | { 125 | continue; 126 | } 127 | ParameterInfo[] parameters = methodInfo.GetParameters(); 128 | if (parameters.Length == 1 && (parameters[0].ParameterType == typeof(IDictionary))) 129 | { 130 | try 131 | { 132 | OwinMainClass = Activator.CreateInstance(type); 133 | } 134 | catch (Exception value) 135 | { 136 | Console.WriteLine("*** AdapterLoader: An exception occurred when the class was created."); 137 | Console.WriteLine("--> File: {0}", assembly.Location); 138 | Console.WriteLine("--> Class: {0}", type.Name); 139 | Console.WriteLine(value); 140 | continue; 141 | } 142 | Delegate @delegate = Delegate.CreateDelegate(typeof(Func, Task>), OwinMainClass, methodInfo); 143 | OwinMain = ((Func, Task>)@delegate); 144 | return true; 145 | } 146 | } 147 | return false; 148 | } 149 | 150 | public bool AdapterLoaderSuccess() 151 | { 152 | return (!string.IsNullOrEmpty(_appRootPath) || !string.IsNullOrEmpty(_htmlRootBinPath)) 153 | && ((!string.IsNullOrEmpty(_htmlRootBinPath) 154 | && FindFromDirectory(_htmlRootBinPath)) || (!string.IsNullOrEmpty(_appRootPath) 155 | && FindFromDirectory(_appRootPath))); 156 | } 157 | 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /OwinDog/Service/SimpleThreadPool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Threading; 4 | 5 | namespace Service 6 | { 7 | public class SimpleThreadPool 8 | { 9 | 10 | private readonly int iCount; 11 | private readonly int MaxCount; 12 | 13 | private readonly AutoResetEvent AutoResetEvent = new AutoResetEvent(false);//设置为false 无信号 当调用set的时候 线程才会启动执行 14 | 15 | private readonly ConcurrentQueue _workerQueue = new ConcurrentQueue(); 16 | 17 | private long CurrentLongTimes; 18 | 19 | private int bInt; 20 | public SimpleThreadPool() : this(0) 21 | { 22 | } 23 | 24 | public SimpleThreadPool(int num) 25 | { 26 | int num2 = Environment.ProcessorCount; 27 | if (num2 < 1) 28 | { 29 | num2 = 1; 30 | } 31 | if (num2 > 128) 32 | { 33 | num2 = 128; 34 | } 35 | if (num < 1) 36 | { 37 | num = num2; 38 | } 39 | if (num < 2) 40 | { 41 | num = 2; 42 | } 43 | if (num > 128) 44 | { 45 | num = 128; 46 | } 47 | iCount = num; 48 | 49 | int num3 = 24 + (int)(Math.Log((double)num2) * 32.0); 50 | MaxCount = iCount + num3; 51 | StartNewThread(); 52 | ActionQueue.AddAction(new Action(AutoIncrement), 100); 53 | } 54 | 55 | public int GetThreadCount() 56 | { 57 | return _workerQueue.Count; 58 | } 59 | 60 | private void AutoIncrement() 61 | { 62 | if (_workerQueue == null || _workerQueue.Count < 1) 63 | { 64 | return; 65 | } 66 | int num = Interlocked.CompareExchange(ref bInt, 0, -1); 67 | if (num >= MaxCount)//超过了最大线程数量 68 | { 69 | return; 70 | } 71 | long num2 = ActionQueue.LongTimes; 72 | 73 | if (num < iCount) 74 | { 75 | if (num < 1 || num2 - CurrentLongTimes >= 500) 76 | { 77 | StartNewThread(); 78 | } 79 | return; 80 | } 81 | int num3 = (num < iCount + (MaxCount - iCount) / 3) ? 3000 : 8000; 82 | if (num2 - CurrentLongTimes < num3) 83 | { 84 | return; 85 | } 86 | StartNewThread(); 87 | } 88 | 89 | public void UnsafeQueueUserWorkItem(Action action, object obj) 90 | { 91 | if (action == null) 92 | { 93 | throw new Exception("SimpleThreadPool Callback Action is null."); 94 | } 95 | _workerQueue.Enqueue(new Worker 96 | { 97 | Action = action, 98 | state = obj 99 | }); 100 | AutoResetEvent.Set(); 101 | } 102 | 103 | private void StartNewThread() 104 | { 105 | //bInt == -1 ? bInt=0:bInt 106 | if (Interlocked.CompareExchange(ref bInt, 0, -1) >= MaxCount) 107 | { 108 | return; 109 | } 110 | try 111 | { 112 | new Thread(new ThreadStart(b)) 113 | { 114 | IsBackground = true 115 | }.Start(); 116 | } 117 | catch 118 | { 119 | return; 120 | } 121 | CurrentLongTimes = ActionQueue.LongTimes; 122 | } 123 | 124 | private void b() 125 | { 126 | int num = Interlocked.Increment(ref bInt); 127 | if (num <= MaxCount) 128 | { 129 | try 130 | { 131 | C(); 132 | } 133 | catch 134 | { 135 | } 136 | } 137 | Interlocked.Decrement(ref bInt); 138 | } 139 | 140 | private void C() 141 | { 142 | long num = 0; 143 | while (true) 144 | { 145 | Worker worker = null; 146 | if (!_workerQueue.TryDequeue(out worker)) 147 | { 148 | worker = null; 149 | } 150 | if (worker == null) 151 | { 152 | int num2 = Interlocked.CompareExchange(ref bInt, 0, -1); 153 | if (num2 > 1) 154 | { 155 | if (num == 0) 156 | { 157 | num = ActionQueue.LongTimes; 158 | } 159 | else if ((ActionQueue.LongTimes - num) > 5000)//当没有action要执行 线程隔5秒自动销毁 160 | { 161 | break; 162 | } 163 | } 164 | AutoResetEvent.WaitOne(1000);// 等待一秒 165 | } 166 | else 167 | { 168 | num = 0; 169 | try 170 | { 171 | worker.Action(worker.state); 172 | } 173 | catch 174 | { 175 | //ignore 176 | } 177 | } 178 | } 179 | } 180 | 181 | 182 | 183 | public class Worker 184 | { 185 | public Action Action; 186 | 187 | public object state; 188 | } 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /OwinDog/OwinDog.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {38FD2383-56A2-408D-8CBF-1E175F8D6488} 8 | Library 9 | Properties 10 | OwinDog 11 | OwinDog 12 | v4.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | true 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | 36 | 37 | true 38 | bin\x64\Debug\ 39 | DEBUG;TRACE 40 | true 41 | full 42 | x64 43 | prompt 44 | MinimumRecommendedRules.ruleset 45 | 46 | 47 | bin\x64\Release\ 48 | TRACE 49 | true 50 | pdbonly 51 | x64 52 | prompt 53 | MinimumRecommendedRules.ruleset 54 | true 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | README.md 120 | 121 | 122 | 123 | 130 | -------------------------------------------------------------------------------- /Owin.WebSocket/Handlers/OwinWebSocket.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Net.WebSockets; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | using Owin.WebSocket.Extensions; 8 | 9 | namespace Owin.WebSocket.Handlers 10 | { 11 | #region 12 | 13 | 14 | 15 | // 异步关闭连的函数代理 16 | using WebSocketCloseAsync = 17 | Func; 22 | 23 | // 异步读取数据的函数代理 24 | using WebSocketReceiveAsync = 25 | Func, // 接受数据的缓冲区 26 | CancellationToken, // 传递操作是否取消 27 | Task< // 返回值 28 | Tuple< 29 | int, // 第一分量,表示接收到的数据类型(1表示本文数据,2表示二进制数据,8表示对方关闭连接) 30 | bool, // 第二分量,表示是否是一个数据帖的最后一块或者独立块 31 | int // 第三分量,表示有效数据的长度 32 | > 33 | > 34 | >; 35 | 36 | 37 | // 异步发送数据的函数代表 38 | using WebSocketSendAsync = 39 | Func, // 待发送的缓冲区 40 | int, // 数据类型,只能是1、2、8 41 | bool, // 这一块数据是否是一条信息的最后一块 42 | CancellationToken, // 取消任务的通知 43 | Task // 返回值 44 | >; 45 | 46 | 47 | #endregion 48 | 49 | 50 | 51 | internal class OwinWebSocket : IWebSocket 52 | { 53 | internal const int CONTINUATION_OP = 0x0; 54 | internal const int TEXT_OP = 0x1; 55 | internal const int BINARY_OP = 0x2; 56 | internal const int CLOSE_OP = 0x8; 57 | internal const int PONG = 0xA; 58 | 59 | private readonly WebSocketSendAsync mSendAsync; 60 | private readonly WebSocketReceiveAsync mReceiveAsync; 61 | private readonly WebSocketCloseAsync mCloseAsync; 62 | private readonly TaskQueue mSendQueue; 63 | 64 | public TaskQueue SendQueue { get { return mSendQueue;} } 65 | 66 | public WebSocketCloseStatus? CloseStatus { get { return null; } } 67 | 68 | public string CloseStatusDescription { get { return null; } } 69 | 70 | public OwinWebSocket(IDictionary owinEnvironment) 71 | { 72 | mSendAsync = (WebSocketSendAsync)owinEnvironment["websocket.SendAsync"]; 73 | mReceiveAsync = (WebSocketReceiveAsync)owinEnvironment["websocket.ReceiveAsync"]; 74 | mCloseAsync = (WebSocketCloseAsync)owinEnvironment["websocket.CloseAsync"]; 75 | mSendQueue = new TaskQueue(); 76 | } 77 | 78 | public Task SendText(ArraySegment data, bool endOfMessage, CancellationToken cancelToken) 79 | { 80 | return Send(data, WebSocketMessageType.Text, endOfMessage, cancelToken); 81 | } 82 | 83 | public Task SendBinary(ArraySegment data, bool endOfMessage, CancellationToken cancelToken) 84 | { 85 | return Send(data, WebSocketMessageType.Binary, endOfMessage, cancelToken); 86 | } 87 | 88 | public Task Send(ArraySegment data, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancelToken) 89 | { 90 | var sendContext = new SendContext(data, endOfMessage, messageType, cancelToken); 91 | 92 | return mSendQueue.Enqueue( 93 | async s => 94 | { 95 | await mSendAsync(s.Buffer, MessageTypeEnumToOpCode(s.Type), s.EndOfMessage, s.CancelToken); 96 | }, 97 | sendContext); 98 | } 99 | 100 | public Task Close(WebSocketCloseStatus closeStatus, string closeDescription, CancellationToken cancelToken) 101 | { 102 | return mCloseAsync((int)closeStatus, closeDescription, cancelToken); 103 | } 104 | 105 | public async Task, WebSocketMessageType>> ReceiveMessage(byte[] buffer, CancellationToken cancelToken) 106 | { 107 | var count = 0; 108 | Tuple result; 109 | int opType = -1; 110 | do 111 | { 112 | var segment = new ArraySegment(buffer, count, buffer.Length - count); 113 | result = await mReceiveAsync(segment, cancelToken); 114 | 115 | count += result.Item3; 116 | if (opType == -1) 117 | opType = result.Item1; 118 | 119 | if (count == buffer.Length && !result.Item2) 120 | throw new InternalBufferOverflowException( 121 | "The Buffer is to small to get the Websocket Message! Increase in the Constructor!"); 122 | } 123 | while (!result.Item2); 124 | 125 | return new Tuple, WebSocketMessageType>(new ArraySegment(buffer, 0, count), MessageTypeOpCodeToEnum(opType)); 126 | } 127 | 128 | private static WebSocketMessageType MessageTypeOpCodeToEnum(int messageType) 129 | { 130 | switch (messageType) 131 | { 132 | case TEXT_OP: 133 | return WebSocketMessageType.Text; 134 | case BINARY_OP: 135 | return WebSocketMessageType.Binary; 136 | case CLOSE_OP: 137 | return WebSocketMessageType.Close; 138 | case PONG: 139 | return WebSocketMessageType.Binary; 140 | default: 141 | throw new ArgumentOutOfRangeException("messageType", messageType, String.Empty); 142 | } 143 | } 144 | 145 | private static int MessageTypeEnumToOpCode(WebSocketMessageType webSocketMessageType) 146 | { 147 | switch (webSocketMessageType) 148 | { 149 | case WebSocketMessageType.Text: 150 | return TEXT_OP; 151 | case WebSocketMessageType.Binary: 152 | return BINARY_OP; 153 | case WebSocketMessageType.Close: 154 | return CLOSE_OP; 155 | default: 156 | throw new ArgumentOutOfRangeException("webSocketMessageType", webSocketMessageType, String.Empty); 157 | } 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /OwinDog/Util/UrlDeCode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Runtime.CompilerServices; 6 | using System.Text; 7 | 8 | namespace Util 9 | { 10 | public class UrlDeCode 11 | { 12 | /// 13 | /// Url解码 默认Utf8 14 | /// 15 | /// 16 | /// 17 | public static string Decode(string text) 18 | { 19 | return Decode(text, Encoding.UTF8); 20 | } 21 | 22 | /// 23 | /// Url解码 24 | /// 25 | /// 26 | /// 27 | /// 28 | public static string Decode(string text, Encoding uTF) 29 | { 30 | if (text == null) 31 | { 32 | return null; 33 | } 34 | if (text.IndexOf('%') == -1 && text.IndexOf('+') == -1) 35 | { 36 | return text; 37 | } 38 | if (uTF == null) 39 | { 40 | uTF = Encoding.UTF8; 41 | } 42 | long num = text.Length; 43 | List list = new List(); 44 | int num2 = 0; 45 | while (num2 < num) 46 | { 47 | char c = text[num2]; 48 | if (c == '%' && (num2 + 2) < num && text[num2 + 1] != '%') 49 | { 50 | int num3; 51 | if (text[num2 + 1] == 'u' && (num2 + 5) < num)//如:字符“中”,UTF-16BE是:“6d93”,因此Escape是“%u6d93” 52 | { 53 | num3 = ChineseParse(text, num2 + 2, 4); 54 | if (num3 != -1) 55 | { 56 | //如果有unicode编码 例如/%u4f60%u597d ➡ /你好 57 | AddToByteList(list, (char)num3, uTF); 58 | num2 += 5; 59 | } 60 | else 61 | { 62 | AddToByteList(list, '%', uTF); 63 | } 64 | } 65 | else if ((num3 = ChineseParse(text, num2 + 1, 2)) != -1) //汉字Url编码 例如 你好 %e4%bd%a0 %e5%a5%bd 66 | { 67 | AddToByteList(list, (char)num3, uTF); 68 | num2 += 2; 69 | } 70 | else 71 | { 72 | AddToByteList(list, '%', uTF); 73 | } 74 | } 75 | else if (c == '+') 76 | { 77 | AddToByteList(list, ' ', uTF); 78 | } 79 | else 80 | { 81 | AddToByteList(list, c, uTF); 82 | } 83 | num2++; 84 | } 85 | byte[] bytes = list.ToArray(); 86 | return uTF.GetString(bytes); 87 | } 88 | 89 | 90 | 91 | 92 | /// 93 | /// 返回0-15 中文 返回-1 94 | /// 95 | /// 96 | /// 97 | private static int Byte2Number(byte b) 98 | { 99 | 100 | if (b >= 48 && b <= 57)//其中48~57为0到9十个阿拉伯数字 101 | { 102 | return (int)(b - 48); 103 | } 104 | if (b >= 97 && b <= 102) //小写的a-f 105 | { 106 | return (int)(b - 97 + 10); 107 | } 108 | if (b >= 65 && b <= 70)//大写A-F 109 | { 110 | return (int)(b - 65 + 10); 111 | } 112 | return -1; 113 | } 114 | 115 | 116 | 117 | /// 118 | /// Char类型转成byte类型 119 | /// 120 | /// 121 | /// 122 | /// 123 | private static void AddToByteList(IList list, char c, Encoding encoding) 124 | { 125 | if (c > 'ÿ') 126 | { 127 | byte[] bytes = encoding.GetBytes(new char[] 128 | { 129 | c 130 | }); 131 | for (int i = 0; i < bytes.Length; i++) 132 | { 133 | byte item = bytes[i]; 134 | list.Add(item); 135 | } 136 | return; 137 | } 138 | list.Add((byte)c); 139 | } 140 | 141 | /// 142 | /// 汉字转成 字节码int类型 143 | /// 144 | /// 145 | /// 146 | /// 147 | /// 148 | private static int ChineseParse(byte[] array, int start, int offset) 149 | { 150 | int num3 = 0; 151 | int num4 = offset + start; 152 | for (int i = start; i < num4; i++) 153 | { 154 | int num5 = Byte2Number(array[i]); 155 | if (num5 == -1) 156 | { 157 | return -1; 158 | } 159 | num3 = (num3 << 4) + num5; 160 | } 161 | return num3; 162 | } 163 | 164 | /// 165 | /// 汉字转成 字节码int类型 166 | /// 167 | /// 168 | /// 169 | /// 170 | /// 171 | private static int ChineseParse(string text, int start, int offset) 172 | { 173 | int num3 = 0; 174 | int num4 = offset + start; 175 | for (int i = start; i < num4; i++) 176 | { 177 | char c = text[i]; 178 | if (c > '\u007f') 179 | { 180 | return -1; 181 | } 182 | int number = Byte2Number((byte)c);//如果不是0-9 A-F a-f 认为是中文 183 | if (number == -1) 184 | { 185 | return -1; 186 | } 187 | num3 = (num3 << 4) + number; 188 | } 189 | return num3; 190 | } 191 | 192 | } 193 | 194 | } 195 | -------------------------------------------------------------------------------- /OwinDog/Util/WebSocketReciveDataParse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Reflection; 5 | using System.Runtime.CompilerServices; 6 | using System.Threading.Tasks; 7 | 8 | namespace OwinEngine 9 | { 10 | /// 11 | /// http://www.cnblogs.com/smark/archive/2012/11/26/2789812.html 12 | /// 13 | internal class WebSocketReciveDataParse 14 | { 15 | private readonly Queue _reciveDataQueue = new Queue(); 16 | 17 | private byte[] _buffs; 18 | 19 | public bool IsEof { get; set; } 20 | 21 | public bool abool { get; set; } 22 | 23 | public ReciveData GetReciveData() 24 | { 25 | ReciveData result; 26 | lock (_reciveDataQueue) 27 | { 28 | if (_reciveDataQueue.Count < 1) 29 | { 30 | result = null; 31 | } 32 | else 33 | { 34 | result = _reciveDataQueue.Dequeue(); 35 | } 36 | } 37 | return result; 38 | } 39 | 40 | 41 | 42 | public void Parse(byte[] array, int srcOffset, int reciveLength) 43 | { 44 | 45 | if (_buffs != null) 46 | { 47 | byte[] tempBytes = new byte[_buffs.Length + reciveLength]; 48 | Buffer.BlockCopy(_buffs, 0, tempBytes, 0, _buffs.Length); 49 | Buffer.BlockCopy(array, srcOffset, tempBytes, _buffs.Length, reciveLength); 50 | array = tempBytes; 51 | _buffs = null; 52 | srcOffset = 0; 53 | reciveLength = tempBytes.Length; 54 | } 55 | if (reciveLength < 2) 56 | { 57 | Fill(array, srcOffset, reciveLength); 58 | return; 59 | } 60 | if (reciveLength > 8388608)//最大值也是8388608bytes(8M) 61 | { 62 | throw new Exception("WebSocket Error: Recvive Data Too Long..."); 63 | } 64 | int index = srcOffset; 65 | //第一个字节 最高位用于描述消息是否结束,如果为1则该消息为消息尾部,如果为零则还有后续数据包 66 | int firstByte = array[0] >> 4;//向右移动四位 array[0]=128 67 | if (firstByte != 8 && firstByte != 0) 68 | { 69 | IsEof = (true); 70 | return; 71 | } 72 | bool flag = firstByte == 8; 73 | int num5 = array[index] & 15;//00001111 1111 0000 0001 0011 0111 1111 0010 0111 0110 0101 清掉X的高4位,而保留 低 4位 最低4位用于描述消息类型,消息类型暂定有15种 74 | index++; 75 | bool flag2 = array[index] >> 7 > 0; 76 | ushort num6 = (ushort)(array[index] & 127);//datalength 77 | index++; //如果 == 126 start = start + 2 == 127 start = start + 8 78 | ulong num7; 79 | if (num6 < 126) 80 | { 81 | num7 = num6; 82 | } 83 | else 84 | { 85 | if (num6 != 126) 86 | { 87 | abool = (true); 88 | IsEof = (true); 89 | return; 90 | } 91 | if (Nokori(srcOffset, reciveLength, index) < 2) 92 | { 93 | Fill(array, srcOffset, reciveLength); 94 | return; 95 | } 96 | num7 = (ulong)((array[index] << 8) + array[index + 1]); 97 | index += 2; 98 | } 99 | byte[] array3 = null; 100 | if (flag2)//是否有 第二位 masks 如果存在掩码的情况下获取4位掩码值: 101 | { 102 | if (Nokori(srcOffset, reciveLength, index) < 4) 103 | { 104 | Fill(array, srcOffset, reciveLength); 105 | return; 106 | } 107 | array3 = new byte[4]; 108 | Buffer.BlockCopy(array, index, array3, 0, 4); 109 | index += 4; 110 | } 111 | if (Nokori(srcOffset, reciveLength, index) < (long)num7) 112 | { 113 | _buffs = new byte[reciveLength]; 114 | Buffer.BlockCopy(array, srcOffset, _buffs, 0, reciveLength);//数据分批读取 115 | return; 116 | } 117 | byte[] array4 = new byte[num7]; 118 | Buffer.BlockCopy(array, index, array4, 0, (int)num7); 119 | index += (int)num7; 120 | if (flag2) 121 | { 122 | for (int i = 0; i < array4.Length; i++) 123 | { 124 | array4[i] ^= array3[i % 4];//获取消息体 125 | } 126 | } 127 | if (num5 == 8) //1000 128 | { 129 | IsEof = (true); 130 | } 131 | if (num5 == 9) // 1001 132 | { 133 | IsEof = (true); 134 | return; 135 | } 136 | if (num5 != 10) //1010 137 | { 138 | lock (_reciveDataQueue) 139 | { 140 | ReciveData item = new ReciveData 141 | { 142 | Data = array4, 143 | IsEof = flag, 144 | BytesLength = (int)num7, 145 | Type = num5 146 | }; 147 | _reciveDataQueue.Enqueue(item); 148 | } 149 | } 150 | int num8 = Nokori(srcOffset, reciveLength, index); 151 | if (num8 < 1) 152 | { 153 | return; 154 | } 155 | Parse(array, index, num8); 156 | } 157 | 158 | private void Fill(byte[] src, int srcOffset, int index) 159 | { 160 | _buffs = new byte[index]; 161 | Buffer.BlockCopy(src, srcOffset, _buffs, 0, index); 162 | } 163 | 164 | private static int Nokori(int srcOffset, int reciveLength, int index) 165 | { 166 | return (srcOffset + reciveLength - index); 167 | } 168 | 169 | 170 | 171 | public class ReciveData 172 | { 173 | public byte[] Data; 174 | /// 175 | /// 第三分量,表示有效数据的长度 176 | /// 177 | 178 | public int BytesLength; 179 | 180 | public bool IsEof; 181 | 182 | /// 183 | /// //数据类型,只能是1、2、8 1表示本文数据,2表示二进制数据,8表示对方关闭连接) 184 | /// 185 | public int Type; 186 | } 187 | } 188 | 189 | } 190 | -------------------------------------------------------------------------------- /OwinDog/Model/WriteHandle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Runtime.InteropServices; 4 | 5 | namespace Model 6 | { 7 | public class WriteHandle : HandleBase 8 | { 9 | private const int BUFFER_COUNT = 4; 10 | 11 | 12 | private IntPtr _bufs; 13 | 14 | private Action _callback; 15 | 16 | private object _state; 17 | 18 | private readonly List _pins = new List(); 19 | 20 | private static readonly int _bufferSize; 21 | 22 | private LoopHandle _loopHandle; 23 | 24 | private static readonly IntPtr _bufferPoint; 25 | 26 | private static readonly LibUv.Write_Callback _Write_Callback = new LibUv.Write_Callback(UvWriteCallback); 27 | static unsafe WriteHandle() 28 | { 29 | _bufferSize = (Marshal.SizeOf(typeof(LibUv.BufferStruct)) * BUFFER_COUNT); 30 | IntPtr value = Marshal.AllocHGlobal(BUFFER_COUNT);//申请4个字节内存 31 | *(int*)((void*)value) = 134744330; 32 | _bufferPoint = value; 33 | } 34 | 35 | public void Init(LoopHandle loopHandle) 36 | { 37 | _loopHandle = loopHandle; 38 | Init(_loopHandle.LibUv, (_loopHandle.LibUv.WriteReqSize + _bufferSize), _loopHandle.LoopRunThreadId); 39 | _bufs = handle + loopHandle.LibUv.WriteReqSize; 40 | } 41 | 42 | public unsafe void Free(UvStreamHandle uvPipeHandle, UvStreamHandle sendHandle, Action callBack, object state) 43 | { 44 | _callback = callBack; 45 | _state = state; 46 | try 47 | { 48 | _pins.Add(GCHandle.Alloc(this, GCHandleType.Normal)); 49 | LibUv.BufferStruct* ptr = (LibUv.BufferStruct*)((void*)_bufs); 50 | *ptr = LibUv.CreateBufferStruct(_bufferPoint, 4); 51 | LibUv.Write2(this, uvPipeHandle, ptr, 1, sendHandle, _Write_Callback); 52 | } 53 | catch 54 | { 55 | HandleFree(this); 56 | sendHandle.Dispose(); 57 | _callback = null; 58 | _state = null; 59 | throw; 60 | } 61 | } 62 | public void Write(UvStreamHandle uvStreamHandle, byte[] buffer1, Action callBack, object state) 63 | { 64 | Write(uvStreamHandle, buffer1, 0, buffer1.Length, null, 0, 0, callBack, state); 65 | } 66 | 67 | public void Write(UvStreamHandle uvStreamHandle, byte[] array, byte[] array2, Action callBack, object state) 68 | { 69 | Write(uvStreamHandle, array, 0, array.Length, array2, 0, (array2 == null) ? 0 : array2.Length, callBack, state); 70 | } 71 | 72 | private unsafe void Write(UvStreamHandle uvStreamHandle, byte[] buffer1, int buffer1StartIndex, int buffer1Offset, byte[] buffer2, int buffer2StartIndex, int buffer2Offset, Action callBack, object state) 73 | { 74 | 75 | if (buffer1 == null || buffer1Offset < 1 || buffer1.Length < buffer1Offset + buffer1StartIndex) 76 | { 77 | throw new ArgumentNullException("buffer1"); 78 | } 79 | _callback = callBack; 80 | _state = state; 81 | try 82 | { 83 | _pins.Add(GCHandle.Alloc(this, GCHandleType.Normal)); 84 | LibUv.BufferStruct* ptr = (LibUv.BufferStruct*)((void*)_bufs); 85 | int nbufs = 0; 86 | GCHandle item = GCHandle.Alloc(buffer1, GCHandleType.Pinned); 87 | _pins.Add(item); 88 | //返回的是对象的“数据区”的起始地址 89 | *ptr = LibUv.CreateBufferStruct(item.AddrOfPinnedObject() + buffer1StartIndex, buffer1Offset); 90 | nbufs++; 91 | if (buffer2 != null && buffer2Offset > 0) 92 | { 93 | if (buffer2.Length < buffer2Offset + buffer2StartIndex) 94 | { 95 | throw new ArgumentException("buffer2"); 96 | } 97 | item = GCHandle.Alloc(buffer2, GCHandleType.Pinned); 98 | _pins.Add(item); 99 | ptr[1] = LibUv.CreateBufferStruct(item.AddrOfPinnedObject() + buffer2StartIndex, buffer2Offset); 100 | nbufs++; 101 | } 102 | //int uv_write(uv_write_t* req, uv_stream_t* handle,uv_buf_t bufs[], int bufcnt, uv_write_cb cb); 103 | LibUv.Write(this, uvStreamHandle, ptr, nbufs, _Write_Callback); 104 | } 105 | catch 106 | { 107 | HandleFree(this); 108 | _callback = null; 109 | _state = null; 110 | throw; 111 | } 112 | } 113 | private static void HandleFree(WriteHandle writeHandle) 114 | { 115 | if (writeHandle._pins.Count < 1) 116 | { 117 | return; 118 | } 119 | foreach (GCHandle current in writeHandle._pins) 120 | { 121 | current.Free(); 122 | } 123 | writeHandle._pins.Clear(); 124 | } 125 | 126 | private static void UvWriteCallback(IntPtr intPtr, int status) 127 | { 128 | WriteHandle writeHandle = GetObjectFromHandel(intPtr); 129 | Action callback = writeHandle._callback; 130 | writeHandle._callback = null; 131 | object state = writeHandle._state; 132 | writeHandle._state = null; 133 | Exception arg = null; 134 | if (status < 0) 135 | { 136 | writeHandle.LibUv.GetException(status, out arg); 137 | } 138 | try 139 | { 140 | callback(status, arg, state); 141 | } 142 | catch (Exception ex) 143 | { 144 | Console.WriteLine("* UvWriteCallback Error:" + Environment.NewLine + ex.ToString()); 145 | } 146 | finally 147 | { 148 | HandleFree(writeHandle); 149 | writeHandle.Close(); 150 | writeHandle.Dispose(); 151 | } 152 | } 153 | 154 | 155 | 156 | protected override bool ReleaseHandle() 157 | { 158 | _Close_Callback(handle); 159 | handle = IntPtr.Zero; 160 | // Marshal.FreeHGlobal(_bufferPoint); 161 | return true; 162 | } 163 | 164 | } 165 | 166 | 167 | } 168 | -------------------------------------------------------------------------------- /OwinDog/OwinEngine/OwinTask.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net.Sockets; 5 | using System.Runtime.CompilerServices; 6 | using System.Text; 7 | using Service; 8 | using Util; 9 | 10 | namespace OwinEngine 11 | { 12 | public static class OwinTask 13 | { 14 | 15 | private static readonly Dictionary _dynamicReqDic; 16 | 17 | private static readonly byte[] Continue100; 18 | 19 | 20 | static OwinTask() 21 | { 22 | _dynamicReqDic = new Dictionary(); 23 | Continue100 = Encoding.ASCII.GetBytes("HTTP/1.1 100 Continue\r\nServer: Owin\r\nX-Owin-Server: OwinDog\r\nContent-Length: 0\r\n\r\n"); 24 | _dynamicReqDic["aspx"] = true; 25 | _dynamicReqDic["ashx"] = true; 26 | _dynamicReqDic["ascx"] = true; 27 | _dynamicReqDic["asmx"] = true; 28 | _dynamicReqDic["svc"] = true; 29 | _dynamicReqDic["cshtml"] = true; 30 | _dynamicReqDic["cshtm"] = true; 31 | _dynamicReqDic["sshtm"] = true; 32 | _dynamicReqDic["sshtml"] = true; 33 | _dynamicReqDic["vbhtml"] = true; 34 | _dynamicReqDic["php"] = true; 35 | _dynamicReqDic["jsp"] = true; 36 | _dynamicReqDic["do"] = true; 37 | } 38 | 39 | /// 40 | /// 用Owin 适配器去执行请求 41 | /// 42 | /// 43 | public static void ExcuteWorkTask(RequestData requestData) 44 | { 45 | try 46 | { 47 | AddWorkTask(requestData); 48 | } 49 | catch (Exception ex) 50 | { 51 | requestData.Socket.Dispose(); 52 | if (!(ex is SocketException)) 53 | { 54 | Console.WriteLine(); 55 | Console.WriteLine("OwinDog DEBUG: ============================================================"); 56 | Console.WriteLine(ex); 57 | } 58 | } 59 | } 60 | 61 | private static void AddWorkTask(RequestData requestData) 62 | { 63 | if (requestData.SafeRequestUrl.Length > 3 && !RequestCheck.IsNotSafeRequest(requestData.SafeRequestUrl)) 64 | { 65 | HttpWorker.EndRequest(requestData.Socket, 400, "Path:" + requestData.SafeRequestUrl); 66 | requestData.SaveToPoll(); 67 | return; 68 | } 69 | string fileExt = CommonUtil.GetFileExtention(requestData.SafeRequestUrl); 70 | if (!string.IsNullOrEmpty(fileExt)) 71 | { 72 | fileExt = fileExt.ToLower(); 73 | } 74 | 75 | #region 静态文件请求处理 76 | 77 | if (!string.IsNullOrEmpty(fileExt) && !_dynamicReqDic.ContainsKey(fileExt) && requestData.HttpMethod == "GET") 78 | { 79 | HttpWorker httpWorker = new HttpWorker(); 80 | if (httpWorker.Process(requestData)) 81 | { 82 | return; 83 | } 84 | } 85 | #endregion 86 | 87 | #region 动态请求处理 88 | if (ApplicationInfo.OwinAdapter != null) 89 | { 90 | if ((requestData.HttpMethod == "POST" || requestData.HttpMethod == "PUT") 91 | && requestData.HeadDomainDic != null && requestData.HeadDomainDic.Keys.Contains("Expect")) 92 | { 93 | //http 100-continue用于客户端在发送POST数据给服务器前,征询服务器情况,看服务器是否处理POST的数据,如果不处理,客户端则不上传POST数据,如果处理,则POST上传数据。在现实应用中,通过在POST大数据时,才会使用100-continue协议。 Client发送Expect:100-continue消息 94 | //在使用curl做POST的时候, 当要POST的数据大于1024字节的时候, curl并不会直接就发起POST请求, 而是会分为俩步, 95 | //1. 发送一个请求, 包含一个Expect:100-continue, 询问Server使用愿意接受数据 96 | //2. 接收到Server返回的100-continue应答以后, 才把数据POST给Server 97 | //大致功能好像是当post数据超过1024时,不用询问服务器是否接受其他数据 98 | string text2 = requestData.HeadDomainDic["Expect"].FirstOrDefault(); 99 | if (string.Equals(text2, "100-continue", StringComparison.OrdinalIgnoreCase)) 100 | { 101 | requestData.Socket.Write(Continue100, WriteCallBack, null); 102 | requestData.HeadDomainDic.Remove("Expect"); 103 | } 104 | } 105 | OwinAdapterManage owinAdapterManage = new OwinAdapterManage(); 106 | if (owinAdapterManage.Process(requestData)) 107 | { 108 | return; 109 | } 110 | } 111 | 112 | #endregion 113 | #region 请求Info信息 114 | 115 | if (requestData.SafeRequestUrl == "/info") 116 | { 117 | SendWelcomePage((OwinSocket)requestData.Socket, requestData); 118 | return; 119 | } 120 | #endregion 121 | 122 | HttpWorker.EndRequest(requestData.Socket, 404, requestData.RequestUrl); 123 | requestData.SaveToPoll(); 124 | } 125 | 126 | 127 | 128 | private static void SendWelcomePage(OwinSocket socket, RequestData requestData) 129 | { 130 | string text = "\r\nOwinDog Server

Hello, OwinDog Host Server!


" + DateTime.Now.ToString("yyy-MM-dd HH:mm:ss") + ""; 131 | string s = string.Format("HTTP/1.1 200 OK\r\nServer: OwinDog/1.0\r\nContent-Length:{0}\r\n\r\n{1}", Encoding.ASCII.GetByteCount(text), text); 132 | socket.Write(Encoding.ASCII.GetBytes(s), new Action(WriteCallBack), requestData); 133 | } 134 | 135 | 136 | 137 | private static void WriteCallBack(OwinSocket socket, int num, Exception ex, object obj) 138 | { 139 | RequestData requestData = obj as RequestData; 140 | if (requestData == null) 141 | { 142 | socket.Dispose(); 143 | return; 144 | } 145 | if (!requestData.IsKeepAlive() || ex != null) 146 | { 147 | requestData.SaveToPoll(); 148 | socket.Dispose(); 149 | return; 150 | } 151 | byte[] preLoadedBody = requestData._preLoadedBody; 152 | requestData.SaveToPoll(); 153 | OwinHttpWorkerManage.Start(socket, preLoadedBody); 154 | } 155 | 156 | 157 | 158 | 159 | 160 | } 161 | 162 | } 163 | -------------------------------------------------------------------------------- /OwinDog/Util/AssemblyUtils.cs: -------------------------------------------------------------------------------- 1 | 2 | 3 | using System; 4 | using System.Collections.Concurrent; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | using System.Reflection; 8 | using Service; 9 | 10 | namespace Util 11 | { 12 | public static class AssemblyUtils 13 | { 14 | private static readonly ConcurrentDictionary _assemblyObject; 15 | 16 | private static readonly ConcurrentDictionary _assemblyConcurrentDictionary; 17 | 18 | private static readonly string[] _assemblyStringArray; 19 | static AssemblyUtils() 20 | { 21 | _assemblyObject = new ConcurrentDictionary(StringComparer.Ordinal); 22 | _assemblyConcurrentDictionary = new ConcurrentDictionary(StringComparer.Ordinal); 23 | List list = new List(); 24 | string text = Path.Combine(ApplicationInfo.Wwwroot, "bin"); 25 | if (!Directory.Exists(text)) 26 | { 27 | text = Path.Combine(new string[] 28 | { 29 | ApplicationInfo.Wwwroot + "Bin" 30 | }); 31 | if (Directory.Exists(text)) 32 | { 33 | list.Add(text); 34 | } 35 | } 36 | else 37 | { 38 | list.Add(text); 39 | } 40 | string text2 = ApplicationInfo.Approot; 41 | if (!string.IsNullOrEmpty(text2) && Directory.Exists(text2)) 42 | { 43 | list.Add(text2); 44 | } 45 | string text3 = ApplicationInfo.AppPtah; 46 | if (!string.IsNullOrEmpty(text3)) 47 | { 48 | text3 = Path.Combine(text3, "lib"); 49 | if (Directory.Exists(text3)) 50 | { 51 | list.Add(text3); 52 | } 53 | } 54 | if (list.Count > 0) 55 | { 56 | string[] array = list.ToArray(); 57 | string[] array2 = array; 58 | for (int i = 0; i < array2.Length; i++) 59 | { 60 | string path = array2[i]; 61 | try 62 | { 63 | string[] directories = Directory.GetDirectories(path); 64 | if (directories.Length > 0) 65 | { 66 | list.AddRange(directories); 67 | } 68 | } 69 | catch 70 | { 71 | //ignore 72 | } 73 | } 74 | _assemblyStringArray = list.ToArray(); 75 | } 76 | } 77 | 78 | public static Assembly AassemblyName(AssemblyName assemblyName) 79 | { 80 | string name = assemblyName.Name; 81 | Assembly assembly; 82 | if (_assemblyConcurrentDictionary.TryGetValue(name, out assembly)) 83 | { 84 | return assembly; 85 | } 86 | object orAdd = _assemblyObject.GetOrAdd(name, new object()); 87 | try 88 | { 89 | lock (orAdd) 90 | { 91 | if (_assemblyConcurrentDictionary.TryGetValue(name, out assembly)) 92 | { 93 | return assembly; 94 | } 95 | assembly = AStr(name); 96 | if (assembly != null) 97 | { 98 | _assemblyConcurrentDictionary[name] = assembly; 99 | } 100 | } 101 | } 102 | finally 103 | { 104 | _assemblyObject.TryRemove(name, out orAdd); 105 | } 106 | return assembly; 107 | } 108 | 109 | public static Assembly AStr(string str) 110 | { 111 | if (_assemblyStringArray == null) 112 | { 113 | return null; 114 | } 115 | string[] a = _assemblyStringArray; 116 | for (int i = 0; i < a.Length; i++) 117 | { 118 | string path = a[i]; 119 | string text = Path.Combine(path, str + ".dll"); 120 | if (File.Exists(text)) 121 | { 122 | return AssemblyFilea(text); 123 | } 124 | } 125 | return null; 126 | } 127 | 128 | public static Assembly AssemblyFilea(string assemblyFile) 129 | { 130 | AssemblyName assemblyName = AssemblyName.GetAssemblyName(assemblyFile); 131 | return AppDomain.CurrentDomain.Load(assemblyName); 132 | } 133 | 134 | public static void AddAssembly(Assembly assembly) 135 | { 136 | //一般情况都项目工程中都有Resources目录 这个方法就是读取该文件夹内的 137 | string[] manifestResourceNames = assembly.GetManifestResourceNames(); 138 | for (int i = 0; i < manifestResourceNames.Length; i++) 139 | { 140 | string text = manifestResourceNames[i]; 141 | //只选择dll 142 | if (!string.IsNullOrEmpty(text) && text.StartsWith("AssemblyNeutral/") && text.EndsWith(".dll")) 143 | { 144 | string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text); 145 | if (!string.IsNullOrEmpty(fileNameWithoutExtension) && !_assemblyConcurrentDictionary.ContainsKey(fileNameWithoutExtension)) 146 | { 147 | Stream manifestResourceStream = assembly.GetManifestResourceStream(text); 148 | Assembly value = Astream2(manifestResourceStream, null); 149 | _assemblyConcurrentDictionary[fileNameWithoutExtension] = value; 150 | } 151 | } 152 | } 153 | } 154 | 155 | private static byte[] Astream(Stream stream) 156 | { 157 | MemoryStream memoryStream = stream as MemoryStream; 158 | if (memoryStream != null) 159 | { 160 | return memoryStream.ToArray(); 161 | } 162 | MemoryStream memoryStream2; 163 | memoryStream = (memoryStream2 = new MemoryStream()); 164 | byte[] result; 165 | try 166 | { 167 | stream.CopyTo(memoryStream); 168 | result = memoryStream.ToArray(); 169 | } 170 | finally 171 | { 172 | if (memoryStream2 != null) 173 | { 174 | ((IDisposable)memoryStream2).Dispose(); 175 | } 176 | } 177 | return result; 178 | } 179 | 180 | public static Assembly Astream2(Stream stream, Stream stream2) 181 | { 182 | byte[] rawAssembly = Astream(stream); 183 | byte[] rawSymbolStore = null; 184 | if (stream2 != null) 185 | { 186 | rawSymbolStore = Astream(stream2); 187 | } 188 | return AppDomain.CurrentDomain.Load(rawAssembly, rawSymbolStore); 189 | } 190 | 191 | } 192 | 193 | } 194 | 195 | -------------------------------------------------------------------------------- /OwinDog/Model/UvStreamHandle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace Model 5 | { 6 | public abstract class UvStreamHandle : HandleBase 7 | { 8 | private static readonly LibUv.Listen_Callback _Listen_Callback = new LibUv.Listen_Callback(UvConnectionCb); 9 | 10 | private static readonly LibUv.Alloc_Callback _Alloc_Callback = new LibUv.Alloc_Callback(Alloc_Callback); 11 | 12 | private static readonly LibUv.Read_Callback _Read_Callback = new LibUv.Read_Callback(UbReadCb); 13 | 14 | 15 | public Action _connectionCB; 16 | 17 | public object _listenState; 18 | 19 | private GCHandle _listenVitality; 20 | 21 | public Func _allocCallback; 22 | 23 | public Action _readCallback; 24 | 25 | public object _readState; 26 | 27 | private GCHandle _GCHandle; 28 | public void ReadStop() 29 | { 30 | if (!_GCHandle.IsAllocated) 31 | { 32 | return; 33 | } 34 | LibUv.ReadStop(this); 35 | LibUv.BufferStruct bufferStruct = LibUv.CreateBufferStruct(IntPtr.Zero, 0); 36 | UbReadCb(handle, 0, ref bufferStruct); 37 | } 38 | 39 | public void Stop() 40 | { 41 | if (!_GCHandle.IsAllocated) 42 | { 43 | return; 44 | } 45 | _allocCallback = null; 46 | _readCallback = null; 47 | _readState = null; 48 | if (_GCHandle.IsAllocated) 49 | { 50 | _GCHandle.Free(); 51 | } 52 | LibUv.ReadStop(this); 53 | } 54 | 55 | public void Accept(UvStreamHandle uvStreamHandle) 56 | { 57 | LibUv.Accept(this, uvStreamHandle); 58 | } 59 | 60 | /// 61 | /// 62 | /// 63 | /// 队列长度 64 | /// 65 | /// 66 | public void Listen(int hdl, Action connectionCallBack, object state) 67 | { 68 | if (_listenVitality.IsAllocated)//如果分配了句柄,则为 true;否则为 false 69 | { 70 | throw new InvalidOperationException("TODO: Listen may not be called more than once"); 71 | } 72 | try 73 | { 74 | _connectionCB = connectionCallBack; 75 | _listenState = state; 76 | _listenVitality = GCHandle.Alloc(this, GCHandleType.Normal); 77 | LibUv.Listen(this, hdl, _Listen_Callback); 78 | } 79 | catch 80 | { 81 | _connectionCB = null; 82 | _listenState = null; 83 | if (_listenVitality.IsAllocated) 84 | { 85 | _listenVitality.Free(); 86 | } 87 | throw; 88 | } 89 | } 90 | private static void UvConnectionCb(IntPtr intPtr, int num) 91 | { 92 | UvStreamHandle uvStreamHandle = GetObjectFromHandel(intPtr); 93 | Exception arg; 94 | num = uvStreamHandle.LibUv.GetException(num, out arg); 95 | try 96 | { 97 | uvStreamHandle._connectionCB(uvStreamHandle, num, arg, uvStreamHandle._listenState); 98 | } 99 | catch (Exception value) 100 | { 101 | Console.WriteLine("DEBUG: UvStreamHandle.UvConnectionCb Call User Function Error:"); 102 | Console.WriteLine(value); 103 | } 104 | } 105 | 106 | public void Read(Func allocCallback, Action readCallback, object obj) 107 | { 108 | if (_GCHandle.IsAllocated) 109 | { 110 | throw new InvalidOperationException("UvStreamHandle.cs: ReadStop must be called before ReadStart may be called again"); 111 | } 112 | try 113 | { 114 | _allocCallback = allocCallback; 115 | _readCallback = readCallback; 116 | _readState = obj; 117 | _GCHandle = GCHandle.Alloc(this, GCHandleType.Normal); 118 | LibUv.ReadStart(this, _Alloc_Callback, _Read_Callback); 119 | } 120 | catch 121 | { 122 | _allocCallback = null; 123 | _readCallback= null; 124 | _readState = null; 125 | if (_GCHandle.IsAllocated) 126 | { 127 | _GCHandle.Free(); 128 | } 129 | throw; 130 | } 131 | } 132 | 133 | /// 134 | /// libuv read 读取 分配内存的回调函数 135 | /// 136 | /// ClientHandle的指针 137 | /// 请求内存大小 138 | /// 139 | private static void Alloc_Callback(IntPtr intPtr, int suggestedSize, out LibUv.BufferStruct buffer) 140 | { 141 | UvStreamHandle uvStreamHandle = GetObjectFromHandel(intPtr); 142 | try 143 | { 144 | buffer = uvStreamHandle._allocCallback(uvStreamHandle, suggestedSize, uvStreamHandle._readState); 145 | } 146 | catch (Exception) 147 | { 148 | buffer = uvStreamHandle.LibUv.CreateBufferStruct(IntPtr.Zero, 0); 149 | throw; 150 | } 151 | } 152 | 153 | /// 154 | /// 155 | /// 156 | /// 157 | /// 158 | /// 159 | private static void UbReadCb(IntPtr intPtr, int num, ref LibUv.BufferStruct ptr) 160 | { 161 | UvStreamHandle uvStreamHandle = GetObjectFromHandel(intPtr); 162 | try 163 | { 164 | if (num < 0) 165 | { 166 | Exception arg; 167 | uvStreamHandle.LibUv.GetException(num, out arg); 168 | uvStreamHandle._readCallback(uvStreamHandle, 0, arg, uvStreamHandle._readState); 169 | } 170 | else 171 | { 172 | uvStreamHandle._readCallback(uvStreamHandle, num, null, uvStreamHandle._readState); 173 | } 174 | } 175 | catch (Exception ex) 176 | { 177 | Console.WriteLine(">>> DEBUG: OwinDog.LibuvApi.UvStreamHandle.UbReadCb: Call UvSocket function error:"); 178 | Console.WriteLine(ex.ToString()); 179 | } 180 | } 181 | 182 | protected override bool ReleaseHandle() 183 | { 184 | if (_listenVitality.IsAllocated) 185 | { 186 | _listenVitality.Free(); 187 | } 188 | if (_GCHandle.IsAllocated) 189 | { 190 | _GCHandle.Free(); 191 | } 192 | return base.ReleaseHandle(); 193 | } 194 | 195 | 196 | } 197 | 198 | } 199 | -------------------------------------------------------------------------------- /OwinDog/OwinEngine/OwinRequestStream.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Runtime.CompilerServices; 7 | using System.Text; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | using Service; 11 | 12 | namespace OwinEngine 13 | { 14 | internal class OwinRequestStream : Stream 15 | { 16 | private readonly Stream _base; 17 | 18 | private int _nextLength; 19 | 20 | public OwinRequestStream(Stream baseStream, int maxReuestLength) 21 | { 22 | _base = baseStream; 23 | _nextLength = maxReuestLength; 24 | } 25 | 26 | 27 | public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object state) 28 | { 29 | if (_nextLength < 1) 30 | { 31 | CustomeAsyncResult customeAsyncResult = new CustomeAsyncResult(state); 32 | customeAsyncResult.RealRecvSize= (-1); 33 | customeAsyncResult.IsCompleted = (true); 34 | customeAsyncResult.RecvBuffer=(buffer); 35 | customeAsyncResult.RecvLength=(count); 36 | customeAsyncResult.RecvOffset=(offset); 37 | customeAsyncResult.UserCallbackFunc=(asyncCallback); 38 | ((AutoResetEvent)customeAsyncResult.AsyncWaitHandle).Set(); 39 | if (asyncCallback != null) 40 | { 41 | asyncCallback.BeginInvoke(customeAsyncResult, null, null); 42 | } 43 | return customeAsyncResult; 44 | } 45 | return _base.BeginRead(buffer, offset, count, asyncCallback, state); 46 | } 47 | 48 | public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object state) 49 | { 50 | throw new NotSupportedException(); 51 | } 52 | 53 | public override void Close() 54 | { 55 | } 56 | 57 | protected override void Dispose(bool disposing) 58 | { 59 | _base.Dispose(); 60 | base.Dispose(disposing); 61 | } 62 | 63 | public override int EndRead(IAsyncResult asyncResult) 64 | { 65 | CustomeAsyncResult customeAsyncResult = (CustomeAsyncResult)asyncResult; 66 | if (customeAsyncResult.RealRecvSize< 0) 67 | { 68 | if (!customeAsyncResult.IsCompleted) 69 | { 70 | customeAsyncResult.IsCompleted = (true); 71 | ((AutoResetEvent)customeAsyncResult.AsyncWaitHandle).Set(); 72 | } 73 | return 0; 74 | } 75 | int num = _base.EndRead(asyncResult); 76 | if (num < 1) 77 | { 78 | return 0; 79 | } 80 | checked 81 | { 82 | _nextLength -= num; 83 | return num; 84 | } 85 | } 86 | 87 | public override void EndWrite(IAsyncResult asyncResult) 88 | { 89 | throw new NotSupportedException(); 90 | } 91 | 92 | public override void Flush() 93 | { 94 | throw new NotSupportedException(); 95 | } 96 | 97 | public override bool CanRead { 98 | get { return true; } 99 | } 100 | 101 | 102 | 103 | public override bool CanSeek { 104 | get 105 | { 106 | return false; 107 | } 108 | } 109 | 110 | 111 | public override bool CanTimeout 112 | { 113 | get{ 114 | return _base.CanTimeout; 115 | } 116 | 117 | } 118 | 119 | public override bool CanWrite 120 | { 121 | get { throw new NotImplementedException(); } 122 | } 123 | 124 | public override long Length 125 | { 126 | get { throw new NotImplementedException(); } 127 | } 128 | 129 | 130 | public override long Position { get; set; } 131 | 132 | 133 | 134 | public override int ReadTimeout 135 | { 136 | get 137 | { 138 | return _base.ReadTimeout; 139 | } 140 | set 141 | { 142 | _base.ReadTimeout = value; 143 | } 144 | } 145 | 146 | 147 | 148 | 149 | public override int Read(byte[] buffer, int offset, int count) 150 | { 151 | if (_nextLength < 1) 152 | { 153 | return 0; 154 | } 155 | int num = _base.Read(buffer, offset, count); 156 | if (num < 0) 157 | { 158 | return 0; 159 | } 160 | checked 161 | { 162 | _nextLength -= num; 163 | return num; 164 | } 165 | } 166 | 167 | public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) 168 | { 169 | TaskCompletionSource taskCompletionSource = new TaskCompletionSource(); 170 | try 171 | { 172 | BeginRead(buffer, offset, count, new AsyncCallback(ReadAsyncCallBack), taskCompletionSource); 173 | } 174 | catch (Exception exception) 175 | { 176 | taskCompletionSource.SetException(exception); 177 | } 178 | return taskCompletionSource.Task; 179 | } 180 | 181 | 182 | 183 | public override int ReadByte() 184 | { 185 | if (_nextLength < 1) 186 | { 187 | return -1; 188 | } 189 | return _base.ReadByte(); 190 | } 191 | 192 | public override long Seek(long num, SeekOrigin seekOrigin) 193 | { 194 | throw new NotSupportedException(); 195 | } 196 | 197 | public override void SetLength(long num) 198 | { 199 | throw new NotSupportedException(); 200 | } 201 | 202 | public override void Write(byte[] array, int num, int num2) 203 | { 204 | throw new NotSupportedException(); 205 | } 206 | 207 | public override void WriteByte(byte b) 208 | { 209 | throw new NotSupportedException(); 210 | } 211 | 212 | 213 | 214 | 215 | private void ReadAsyncCallBack(IAsyncResult asyncResult) 216 | { 217 | CustomeAsyncResult customeAsyncResult = (CustomeAsyncResult)asyncResult; 218 | TaskCompletionSource taskCompletionSource = (TaskCompletionSource)customeAsyncResult.AsyncState; 219 | if (customeAsyncResult.SocketIsErrOrClose || customeAsyncResult.SocketIsTimeOut || customeAsyncResult.RealRecvSize < 0) 220 | { 221 | taskCompletionSource.SetException(new Exception("socket error.")); 222 | return; 223 | } 224 | int num = customeAsyncResult.RealRecvSize; 225 | if (num < 1) 226 | { 227 | num = 0; 228 | } 229 | checked 230 | { 231 | _nextLength -= num; 232 | taskCompletionSource.SetResult(num); 233 | } 234 | } 235 | } 236 | 237 | } 238 | 239 | 240 | -------------------------------------------------------------------------------- /Demo/Nancy.Demo2/Nancy.Demo2.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | 8 | 9 | 2.0 10 | {9DA5F38D-839C-4F81-A7D5-A397AAF14F23} 11 | {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} 12 | Library 13 | Properties 14 | Nancy.Demo2 15 | Nancy.Demo2 16 | v4.5 17 | true 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | true 26 | full 27 | false 28 | bin\ 29 | DEBUG;TRACE 30 | prompt 31 | 4 32 | 33 | 34 | pdbonly 35 | true 36 | bin\ 37 | TRACE 38 | prompt 39 | 4 40 | 41 | 42 | 43 | 44 | ..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll 45 | 46 | 47 | ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll 48 | False 49 | 50 | 51 | ..\packages\Nancy.1.2.0\lib\net40\Nancy.dll 52 | 53 | 54 | ..\packages\Nancy.Owin.1.2.0\lib\net40\Nancy.Owin.dll 55 | 56 | 57 | ..\packages\Nancy.Viewengines.Razor.1.2.0\lib\net40\Nancy.ViewEngines.Razor.dll 58 | 59 | 60 | ..\packages\Owin.1.0\lib\net40\Owin.dll 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | ..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.Helpers.dll 73 | False 74 | 75 | 76 | ..\packages\Microsoft.AspNet.Razor.3.2.2\lib\net45\System.Web.Razor.dll 77 | True 78 | 79 | 80 | ..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.WebPages.dll 81 | True 82 | 83 | 84 | ..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.WebPages.Deployment.dll 85 | False 86 | 87 | 88 | ..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.WebPages.Razor.dll 89 | False 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | Web.config 118 | 119 | 120 | Web.config 121 | 122 | 123 | 124 | 10.0 125 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | True 135 | True 136 | 11613 137 | / 138 | http://localhost:11609/ 139 | False 140 | False 141 | 142 | 143 | False 144 | 145 | 146 | 147 | 148 | 155 | -------------------------------------------------------------------------------- /OwinDog/Service/HttpMimeTypeManage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | 5 | namespace Service 6 | { 7 | public static class HttpMimeTypeManage 8 | { 9 | private static readonly Dictionary _httpMimeTypes; 10 | static HttpMimeTypeManage() 11 | { 12 | _httpMimeTypes = new Dictionary(); 13 | Add("htm", "text/html"); 14 | Add("html", "text/html"); 15 | Add("asp", "text/html"); 16 | Add("aspx", "text/html"); 17 | Add("vbs", "text/html"); 18 | Add("stm", "text/html"); 19 | Add("shtm", "text/html"); 20 | Add("shtml", "text/html"); 21 | Add("hxt", "text/html"); 22 | Add("php", "text/html"); 23 | Add("htt", "text/webviewhtml"); 24 | Add("rm", "application/vnd.rn-realmedia"); 25 | Add("rmvb", "application/vnd.rn-realmedia"); 26 | Add("ra", "audio/x-pn-realaudio"); 27 | Add("ram", "audio/x-pn-realaudio"); 28 | Add("rpm", "audio/x-pn-realaudio-plugin"); 29 | Add("wmv", "audio/wav"); 30 | Add("asf", "video/x-ms-asf"); 31 | Add("asr", "video/x-ms-asf"); 32 | Add("asx", "video/x-ms-asf"); 33 | Add("wmf", "application/x-msmetafile"); 34 | Add("au", "audio/basic"); 35 | Add("mpg", "video/mpeg"); 36 | Add("dat", "video/mpeg"); 37 | Add("vob", "video/mpeg"); 38 | Add("mpeg", "video/mpeg"); 39 | Add("doc", "application/msword"); 40 | Add("docx", "application/msword"); 41 | Add("dot", "application/msword"); 42 | Add("wps", "application/vnd.ms-works"); 43 | Add("wri", "application/x-mswrite"); 44 | Add("xla", "application/vnd.ms-excel"); 45 | Add("xlc", "application/vnd.ms-excel"); 46 | Add("xlm", "application/vnd.ms-excel"); 47 | Add("xls", "application/vnd.ms-excel"); 48 | Add("xlt", "application/vnd.ms-excel"); 49 | Add("xlw", "application/vnd.ms-excel"); 50 | Add("pdf", "application/pdf"); 51 | Add("ppt", "application/vnd.ms-powerpoint"); 52 | Add("pot", "application/vnd.ms-powerpoint"); 53 | Add("rtf", "application/rtf"); 54 | Add("rtx", "text/richtext"); 55 | Add("crt", "application/x-x509-ca-cert"); 56 | Add("der", "application/x-x509-ca-cert"); 57 | Add("movie", "video/x-sgi-movie"); 58 | Add("mp3", "audio/mpeg"); 59 | Add("mp2", "audio/mpeg"); 60 | Add("mpe", "audio/mpeg"); 61 | Add("mpa", "audio/mpeg"); 62 | Add("mp4", "video/mp4"); 63 | Add("mov", "video/quicktime"); 64 | Add("qt", "video/quicktime"); 65 | Add("qtl", "application/x-quicktimeplayer"); 66 | Add("avi", "video/x-msvideo"); 67 | Add("swf", "application/x-shockwave-flash"); 68 | Add("flv", "flv-application/octet-stream"); 69 | Add("mid", "audio/mid"); 70 | Add("midi", "audio/mid"); 71 | Add("rmi", "audio/mid"); 72 | Add("xamp", "application/xaml+xml"); 73 | Add("xaml", "application/xaml+xml"); 74 | Add("xap", "application/x-silverlight-app"); 75 | Add("mf", "application/manifest"); 76 | Add("manifest", "application/manifest"); 77 | Add("application", "application/x-ms-application"); 78 | Add("xbap", "application/x-ms-xbap"); 79 | Add("deploy", "application/octet-stream"); 80 | Add("xps", "application/vnd.ms-xpsdocument"); 81 | Add("xml", "text/xml"); 82 | Add("xsl", "text/xml"); 83 | Add("xslt", "text/xml"); 84 | Add("xsd", "text/xml"); 85 | Add("xsf", "text/xml"); 86 | Add("dtd", "text/xml"); 87 | Add("ism", "text/xml"); 88 | Add("ismc", "text/xml"); 89 | Add("js", "application/x-javascript"); 90 | Add("json", "application/json"); 91 | Add("txt", "text/plain"); 92 | Add("bas", "text/plain"); 93 | Add("c", "text/plain"); 94 | Add("h", "text/plain"); 95 | Add("cpp", "text/plain"); 96 | Add("pas", "text/plain"); 97 | Add("sh", "application/x-sh"); 98 | Add("mht", "message/rfc822"); 99 | Add("mhtml", "message/rfc822"); 100 | Add("eml", "message/rfc822"); 101 | Add("news", "message/rfc822"); 102 | Add("jpe", "image/jpeg"); 103 | Add("jpg", "image/jpeg"); 104 | Add("jpeg", "image/jpeg"); 105 | Add("gif", "image/gif"); 106 | Add("bmp", "image/bmp"); 107 | Add("ico", "image/x-ico"); 108 | Add("tif", "image/tiff"); 109 | Add("tiff", "image/tiff"); 110 | Add("png", "image/png"); 111 | Add("pnz", "image/png"); 112 | Add("svg", "image/svg+xml"); 113 | Add("woff", "application/x-font-woff"); 114 | Add("woff2", "application/x-font-woff"); 115 | Add("ttf", "application/x-font-truetype"); 116 | Add("otf", "application/x-font-opentype"); 117 | Add("eot", "application/vnd.ms-fontobject"); 118 | Add("css", "text/css"); 119 | Add("wml", "text/vnd.wap.wml"); 120 | Add("wmlc", "application/vnd.wap.wmlc"); 121 | Add("wmls", "text/vnd.wap.wmlscript"); 122 | Add("wmlsc", "application/vnd.wap.wmlscriptc"); 123 | Add("wbmp", "image/vnd.wap.wbmp"); 124 | Add("wsc", "application/vnd.wap/wmlscriptc"); 125 | Add("jad", "text/vnd.sun.j2me.app-descriptor"); 126 | Add("jar", "application/java-archive"); 127 | Add("sis", "application/vnd.symbian.install"); 128 | Add("amr", "audio/amr"); 129 | Add("pmd", "audio/pmd"); 130 | Add("3gp", "video/3gpp"); 131 | Add("ogg", "audio/ogg"); 132 | Add("flac", "audio/flac"); 133 | Add("aac", "audio/aac"); 134 | Add("webm", "video/webm"); 135 | Add("gz", "application/x-gzip"); 136 | Add("bz2", "application/x-bzip2"); 137 | Add("tar", "application/x-tar"); 138 | Add("gtar", "application/x-gtar"); 139 | Add("tgz", "application/x-compressed"); 140 | Add("zip", "application/x-zip-compressed"); 141 | Add("java", "application/octet-stream"); 142 | Add("jpb", "application/octet-stream"); 143 | Add("jck", "application/liquidmotion"); 144 | Add("jcz", "application/liquidmotion"); 145 | Add("apk", "application/vnd.android.package-archive"); 146 | Add("ipa", "application/iphone"); 147 | Add("pxl", "application/iphone"); 148 | Add("ipk", "application/vnd.webos.ipk"); 149 | Add("cab", "application/vnd.cab-com-archive"); 150 | Add("ipa", "application/iphone-package-archive"); 151 | Add("deb", "application/x-debian-package-archive"); 152 | Add("xap", "application/x-silverlight-app"); 153 | Add("sisx", "application/vnd.symbian.epoc/x-sisx-app"); 154 | } 155 | 156 | public static string GetHttpMimeType(string text) 157 | { 158 | if (string.IsNullOrEmpty(text)) 159 | { 160 | return "application/octet-stream"; 161 | } 162 | text = text.ToLower(); 163 | string result; 164 | if (!_httpMimeTypes.TryGetValue(text, out result)) 165 | { 166 | return "application/octet-stream"; 167 | } 168 | return result; 169 | } 170 | 171 | public static void Add(string key, string value) 172 | { 173 | key = key.Trim(); 174 | if (string.IsNullOrEmpty(key)) 175 | { 176 | return; 177 | } 178 | if (key[0] == '.') 179 | { 180 | key = key.Substring(1); 181 | } 182 | key = key.ToLower(); 183 | _httpMimeTypes[key] = value; 184 | } 185 | 186 | 187 | } 188 | 189 | 190 | } 191 | -------------------------------------------------------------------------------- /Owin.AspEngine/AspEngine/AspNet.cs: -------------------------------------------------------------------------------- 1 | namespace Owin.AspEngine 2 | { 3 | using System; 4 | using System.Collections.Concurrent; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | using System.Runtime.CompilerServices; 8 | using System.Runtime.InteropServices; 9 | using System.Threading; 10 | using System.Threading.Tasks; 11 | using System.Web.Hosting; 12 | 13 | public static class AspNet 14 | { 15 | private static AppFunc _appFunc; 16 | private static AspApplicationHost _appHost; 17 | private static bool _aspunloading = false; 18 | private static readonly AspRequestBroker _broker; 19 | private static int _ids = 10; 20 | private static object _lckCreateHost = new object(); 21 | private static readonly string _pPath = AppDomain.CurrentDomain.GetData(".appPath").ToString(); 22 | private static ConcurrentDictionary _tasks = new ConcurrentDictionary(); 23 | 24 | static AspNet() 25 | { 26 | //工作路径 27 | Environment.CurrentDirectory = AppDomain.CurrentDomain.BaseDirectory; 28 | 29 | //执行代理 30 | _broker = new AspRequestBroker(new AspRequestBroker.DelegateRead(AspNet.Read), new AspRequestBroker.DelegateWrite(AspNet.Write), new AspRequestBroker.DelegateWriteHeader(AspNet.WriteHeader), new AspRequestBroker.DelegateWriteHttpStatus(AspNet.WriteStatus), new AspRequestBroker.DelegateRequestEnd(AspNet.RequestEnd), new AspRequestBroker.DelegateDomainUnload(AspNet.AspUnload)); 31 | } 32 | 33 | /// 34 | /// 卸载 35 | /// 36 | private static void AspUnload() 37 | { 38 | _aspunloading = true; 39 | Console.WriteLine(" * Asp Applicaton unload....."); 40 | _appHost = null; 41 | _appFunc = null; 42 | if (_tasks.Count > 0) 43 | { 44 | foreach (ReqInfo info in _tasks.Values) 45 | { 46 | info.RequestWorkTask.SetCanceled(); 47 | } 48 | _tasks.Clear(); 49 | } 50 | _aspunloading = false; 51 | } 52 | 53 | private static void CreateAspApplicationHost() 54 | { 55 | //创建并配置用于承载 ASP.NET 的应用程序域。 56 | _appHost = (AspApplicationHost) ApplicationHost.CreateApplicationHost(typeof(AspApplicationHost), "/", _pPath); 57 | _appHost.SetRequestBroker(_broker); 58 | //请求执行委托 59 | _appFunc = new AppFunc(_appHost.Process); 60 | } 61 | 62 | private static int CreateId() 63 | { 64 | int num = Interlocked.Increment(ref _ids); 65 | if (num > 0x7fffd8ef) //int32最大数的一半 66 | { 67 | Interlocked.Exchange(ref _ids, 10); 68 | } 69 | return num; 70 | } 71 | 72 | public static Task Process(IDictionary env) 73 | { 74 | if (_aspunloading) 75 | { 76 | return Task.FromResult(true); 77 | } 78 | if (_appHost == null) 79 | { 80 | lock (_lckCreateHost) 81 | { 82 | if (_appHost == null) 83 | { 84 | CreateAspApplicationHost(); 85 | } 86 | } 87 | } 88 | if (_appHost == null) 89 | { 90 | return null; 91 | } 92 | int reqid = CreateId(); 93 | ReqInfo info = new ReqInfo(env); 94 | AspRequestData data = new AspRequestData(reqid, env); 95 | _tasks[reqid] = info; 96 | RealProcess(data); 97 | return info.RequestWorkTask.Task; 98 | } 99 | 100 | private static void RealProcess(AspRequestData data) 101 | { 102 | try 103 | { 104 | _appFunc(data);//真正的处理request请求 105 | } 106 | catch (Exception) 107 | { 108 | RequestEnd(data.RequestId, false); 109 | } 110 | } 111 | 112 | private static void RequestEnd(int id, bool iskeep) 113 | { 114 | ReqInfo info = null; 115 | if (_tasks.TryRemove(id, out info)) 116 | { 117 | if (iskeep) 118 | { 119 | info.RequestWorkTask.SetResult(true); 120 | } 121 | else 122 | { 123 | info.RequestWorkTask.SetCanceled(); 124 | } 125 | } 126 | } 127 | 128 | 129 | /// 130 | /// 往input 流 读入 131 | /// 132 | /// 133 | /// 134 | /// 135 | /// 136 | /// 137 | private static int Read(int id, byte[] buffer, int offset, int size) 138 | { 139 | ReqInfo info = _tasks[id]; 140 | return info.ReadStream.Read(buffer, offset, size); 141 | } 142 | 143 | /// 144 | /// 往out 流 写入 145 | /// 146 | /// 147 | /// 148 | /// 149 | /// 150 | private static void Write(int id, byte[] buffer, int offset, int size) 151 | { 152 | ReqInfo info = _tasks[id]; 153 | info.WriteStream.Write(buffer, offset, size); 154 | } 155 | 156 | /// 157 | /// 写Response Header 158 | /// 159 | /// 160 | /// 161 | /// 162 | private static void WriteHeader(int id, string name, string value) 163 | { 164 | ReqInfo info = _tasks[id]; 165 | info.ResponseHeader[name] = new string[] { value }; 166 | } 167 | 168 | /// 169 | /// 写状态和描述 170 | /// 171 | /// 172 | /// 173 | /// 174 | private static void WriteStatus(int id, int statusCode, string statusDesc) 175 | { 176 | _tasks[id].WriteStauts(statusCode, statusDesc); 177 | } 178 | 179 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 180 | private delegate void AppFunc(AspRequestData data); 181 | 182 | private class ReqInfo 183 | { 184 | /// 185 | /// Owin环境变量 186 | /// 187 | private IDictionary _env; 188 | 189 | public ReqInfo(IDictionary env) 190 | { 191 | this._env = env; 192 | this.RequestWorkTask = new TaskCompletionSource(); 193 | this.ReadStream = env["owin.RequestBody"] as Stream; 194 | this.WriteStream = env["owin.ResponseBody"] as Stream; 195 | this.ResponseHeader = env["owin.ResponseHeaders"] as IDictionary; 196 | } 197 | 198 | /// 199 | /// 返回码和描述 200 | /// 201 | /// 202 | /// 203 | public void WriteStauts(int code, string desc) 204 | { 205 | this._env["owin.ResponseStatusCode"] = code; 206 | if (!string.IsNullOrEmpty(desc)) 207 | { 208 | this._env["owin.ResponseReasonPhrase"] = desc; 209 | } 210 | } 211 | 212 | /// 213 | /// 读的流 214 | /// 215 | public Stream ReadStream { get; private set; } 216 | 217 | /// 218 | /// 手动控制任务工作流 使用 TaskCompletionSource 类将基于事件的异步操作转换为 Task 219 | /// 220 | public TaskCompletionSource RequestWorkTask { get; private set; } 221 | 222 | /// 223 | /// 返回头 224 | /// 225 | 226 | public IDictionary ResponseHeader { get; private set; } 227 | 228 | /// 229 | /// 写的流 230 | /// 231 | public Stream WriteStream { get; private set; } 232 | } 233 | } 234 | } 235 | 236 | --------------------------------------------------------------------------------