当客户端丢失连接时,SignalR Owin Linux / Mono SocketException上的自主机

我正在运行非常简单的信号服务器自主通过欧文在Ubuntu的服务器14.04,单声道3.2.8。 (代码如下)。

连接/断开连接在远程Windows服务器上以及将位部署到Linux服务器时均正常工作。 但是,当一个客户端意外死亡,而不是告诉信号员他断开连接,那就是当我只在linux服务器上得到一个永无止境的SocketException。 大约30秒左右之后,Windows服务器断开客户端连接,但是linux服务器每隔10秒左右就会发出一次socketexception(也在下面)。

当运行相同的代码时,如何让linux服务器像Windows服务器一样工作,在设置超时后断开用户连接,而不是抛出socketexceptions?

服务器代码:

using System; using System.Threading.Tasks; using Microsoft.AspNet.SignalR; using Owin; namespace signalrtestserver { class Program { static void Main(string[] args) { var uri = System.Configuration.ConfigurationManager.AppSettings["startup_uri"] ?? "http://*:7890"; using (Microsoft.Owin.Hosting.WebApp.Start<Startup>(uri)) { Console.WriteLine(string.Format("Server started on {0}. Press enter to close.", uri)); Console.ReadLine(); } } } class Startup { static Hub hub; public void Configuration(IAppBuilder app) { app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll); var configuration = new HubConfiguration(); configuration.EnableDetailedErrors = true; app.MapSignalR("/signalr", configuration); hub = new MyHub(); } } public class MyHub : Hub { public override Task OnConnected() { Console.WriteLine(Context.ConnectionId + " connected"); return base.OnConnected(); } public override Task OnDisconnected() { Console.WriteLine(Context.ConnectionId + " disconnected"); return base.OnDisconnected(); } public override Task OnReconnected() { Console.WriteLine(Context.ConnectionId + " reconnected"); return base.OnReconnected(); } } } 

客户代码:

 using System; using System.Net; using Microsoft.AspNet.SignalR.Client; namespace signalrconnection { class Program { static void Main(string[] args) { var uri = System.Configuration.ConfigurationManager.AppSettings["signalr_uri"] ?? "http://localhost:7890/signalr"; ServicePointManager.DefaultConnectionLimit = 10; var hubConnection = new HubConnection(uri, false); hubConnection.StateChanged += stateChange => Console.WriteLine(string.Format("SignalR {0} >> {1} ({2})", stateChange.OldState, stateChange.NewState, hubConnection.Transport == null ? "<<null>>" : hubConnection.Transport.Name)); var hubProxy = hubConnection.CreateHubProxy("MyHub"); hubConnection.Start(); Console.WriteLine("Press enter to die..."); Console.ReadLine(); //hubConnection.Dispose(); //uncomment this to simulate a graceful disconnect which works on both windows and linux } } } 

永不结束单音例外:

 {path-to-project}/Microsoft.AspNet.SignalR.Core.dll Error : 0 : SignalR exception thrown by Task: System.AggregateException: One or more errors occured ---> System.IO.IOException: Write failure ---> System.Net.Sockets.SocketException: Connection reset by peer at System.Net.Sockets.Socket.Send (System.Byte[] buf, Int32 offset, Int32 size, SocketFlags flags) [0x00000] in <filename unknown>:0 at System.Net.Sockets.NetworkStream.Write (System.Byte[] buffer, Int32 offset, Int32 size) [0x00000] in <filename unknown>:0 --- End of inner exception stack trace --- at System.Net.Sockets.NetworkStream.Write (System.Byte[] buffer, Int32 offset, Int32 size) [0x00000] in <filename unknown>:0 at System.Net.ResponseStream.InternalWrite (System.Byte[] buffer, Int32 offset, Int32 count) [0x00000] in <filename unknown>:0 at System.Net.ResponseStream.Write (System.Byte[] buffer, Int32 offset, Int32 count) [0x00000] in <filename unknown>:0 at Microsoft.Owin.Host.HttpListener.RequestProcessing.ExceptionFilterStream.Write (System.Byte[] buffer, Int32 offset, Int32 count) [0x00000] in <filename unknown>:0 --- End of inner exception stack trace --- --> (Inner exception 0) System.IO.IOException: Write failure ---> System.Net.Sockets.SocketException: Connection reset by peer at System.Net.Sockets.Socket.Send (System.Byte[] buf, Int32 offset, Int32 size, SocketFlags flags) [0x00000] in <filename unknown>:0 at System.Net.Sockets.NetworkStream.Write (System.Byte[] buffer, Int32 offset, Int32 size) [0x00000] in <filename unknown>:0 --- End of inner exception stack trace --- at System.Net.Sockets.NetworkStream.Write (System.Byte[] buffer, Int32 offset, Int32 size) [0x00000] in <filename unknown>:0 at System.Net.ResponseStream.InternalWrite (System.Byte[] buffer, Int32 offset, Int32 count) [0x00000] in <filename unknown>:0 at System.Net.ResponseStream.Write (System.Byte[] buffer, Int32 offset, Int32 count) [0x00000] in <filename unknown>:0 at Microsoft.Owin.Host.HttpListener.RequestProcessing.ExceptionFilterStream.Write (System.Byte[] buffer, Int32 offset, Int32 count) [0x00000] in <filename unknown>:0 

任何帮助将非常感激。 提前致谢!

Solutions Collecting From Web of "当客户端丢失连接时,SignalR Owin Linux / Mono SocketException上的自主机"

问题是这行static Hub hub ,这一个hub = new MyHub()在您的启动方法。

您不需要显式创建Hub类的实例,也不需要保留参考。 集线器类在对服务器的每个请求中被实例化。 请参阅http://www.asp.net/signalr/overview/signalr-20/hubs-api/hubs-api-guide-server#transience有&#x5173;Hub对象生命周期的部分。

这意味着,无论何时出现断开连接,Linux中的Mono都会在Windows中抛出与MS.NET不同的异常。 SignalR是由最有可能使用MS.NET的人实现的,因此SignalR必须期待某些异常并对此信以为真。

解决这个问题的最好方法是调试进入SignalR实现的代码(当在Mono上运行Linux时),看看异常被捕获的位置,并比较Windows下MS.NET中SignalR的情况。 然后创建一个关于差异的最小测试用例,并在http://bugzilla.xamarin.com/中提交一个错误,他们可能很快就会修复它(或者你可以把它分配给我,我会看看它,因为我有兴趣在单声道下运行SignalR)&#x3002;

我有与简单的Owin自己托管的演示应用程序在树莓派上相同的问题。 通过按住F5从单个浏览器请求“欢迎”页面足以在15秒内杀死主机。 我还没有做过任何自动压力测试,因为我的“用户接受度”测试马上就失败了。

我发现的可靠解决方案是创建自定义的OwinMiddleware来捕获和堵塞套接字异常:

 class CustomExceptionMiddleware : OwinMiddleware { public CustomExceptionMiddleware(OwinMiddleware next) : base(next) { } public override async Task Invoke(IOwinContext context) { try { await Next.Invoke(context); } catch (IOException ex) { Console.WriteLine(ex.Message); } } } 

Owin的启动将需要更新以使用中间件:

 using Owin; public class Startup { public void Configuration(IAppBuilder app) { app.Use<OwnExceptionMiddleware>() .UseNancy(); } } 

它的灵感来自http://dhickey.ie/2014/02/bubbling-exceptions-in-nancy-up-the-owin-pipeline/

这里是我的例外,供参考:

 Unhandled Exception: System.IO.IOException: Write failure ---> System.Net.Sockets.SocketException: The socket has been shut down at System.Net.Sockets.Socket.Send (System.Byte[] buf, Int32 offset, Int32 size, SocketFlags flags) [0x00000] in <filename unknown>:0 at System.Net.Sockets.NetworkStream.Write (System.Byte[] buffer, Int32 offset, Int32 size) [0x00000] in <filename unknown>:0 --- End of inner exception stack trace --- at System.Net.Sockets.NetworkStream.Write (System.Byte[] buffer, Int32 offset, Int32 size) [0x00000] in <filename unknown>:0 at System.Net.ResponseStream.InternalWrite (System.Byte[] buffer, Int32 offset, Int32 count) [0x00000] in <filename unknown>:0 at System.Net.ResponseStream.Close () [0x00000] in <filename unknown>:0 at System.Net.HttpConnection.Close (Boolean force_close) [0x00000] in <filename unknown>:0 at System.Net.HttplistnerResponse.Close (Boolean force) [0x00000] in <filename unknown>:0 at System.Net.HttplistnerResponse.Abort () [0x00000] in <filename unknown>:0 at Microsoft.Owin.Host.Httplistner.RequestProcessing.OwinHttplistnerResponse.End () [0x00000] in <filename unknown>:0 at Microsoft.Owin.Host.Httplistner.RequestProcessing.OwinHttplistnerContext.End () [0x00000] in <filename unknown>:0 at Microsoft.Owin.Host.Httplistner.RequestProcessing.OwinHttplistnerContext.End (System.Exception ex) [0x00000] in <filename unknown>:0 at Microsoft.Owin.Host.Httplistner.OwinHttplistner+<ProcessRequestAsync>d__5.MoveNext () [0x00000] in <filename unknown>:0 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x00000] in <filename unknown>:0 at System.Runtime.CompilerServices.TaskAwaiter.GetResult () [0x00000] in <filename unknown>:0 at Microsoft.Owin.Host.Httplistner.OwinHttplistner+<ProcessRequestsAsync>d__0.MoveNext () [0x00000] in <filename unknown>:0 

考虑一下你在截取的例外情况:

  public override async Task Invoke(IOwinContext context) { try { await Next.Invoke(context); } catch (IOException ex) { if (ex.HResult == -2146233087) // The socket has been shut down { NLog.LogManager.GetLogger("OwinExceptionHandler").Trace(ex); } else { throw; } } } 

我觉得我有同样的问题。 我描述了它:

我已经找到了我的情况的解决方案。 我在OWIN配置方法中将Httplistner.IgnoreWriteExceptions属性设置为“true”,然后注册中间件。 例如:

 internal class Startup { public void Configuration(IAppBuilder app) { object httplistner; if (app.Properties.TryGetValue(typeof(Httplistner).FullName, out httplistner) && httplistner is Httplistner) { // Httplistner should not return exceptions that occur // when sending the response to the client ((Httplistner)httplistner).IgnoreWriteExceptions = true; } app.Use<TestOwinMiddleware>(); } } 

我希望这可以帮助你。