我在ubuntu服务器14.04上运行非常简单的信号服务器,通过Owin自托管,单声道3.2.8。 (以下代码)。
连接/断开连接在远程Windows服务器和我将位部署到Linux服务器时都能正常工作。但是当客户端意外死亡而不是告诉信号器他正在断开连接时,那只是在我只在Linux服务器上得到一个永无止境的SocketException时。 Windows服务器在大约30秒左右后断开客户端,但是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
非常感谢任何帮助。提前谢谢!
答案 0 :(得分:5)
问题是此行static Hub hub
,以及启动方法中的这一行hub = new MyHub()
。
您不需要显式创建Hub类的实例,也不需要保留引用。每次向服务器发出请求时都会实例化集线器类。看到 http://www.asp.net/signalr/overview/signalr-20/hubs-api/hubs-api-guide-server#transience关于集线器对象生存期的部分。
答案 1 :(得分:3)
这意味着每当断开连接时,Linux中的Mono就会抛出与Windows中的MS.NET不同的异常。 SignalR由最有可能使用MS.NET的人实施,因此SignalR必须期待某些异常,并且对此有所了解。
解决此问题的最佳方法是调试代码步进SignalR实现(在使用Mono的Linux上运行时),以查看捕获的异常位置,并与Windows中MS.NET下的SignalR进行比较。然后创建一个关于差异的最小测试用例并在http://bugzilla.xamarin.com/中提交一个错误,他们可能会很快修复它(或者你可以将它分配给我,我会看看它,因为我有兴趣运行SignalR在单声道下。)
答案 2 :(得分:3)
我在Raspberry Pi上使用简单的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.HttpListenerResponse.Close (Boolean force) [0x00000] in <filename unknown>:0
at System.Net.HttpListenerResponse.Abort () [0x00000] in <filename unknown>:0
at Microsoft.Owin.Host.HttpListener.RequestProcessing.OwinHttpListenerResponse.End () [0x00000] in <filename unknown>:0
at Microsoft.Owin.Host.HttpListener.RequestProcessing.OwinHttpListenerContext.End () [0x00000] in <filename unknown>:0
at Microsoft.Owin.Host.HttpListener.RequestProcessing.OwinHttpListenerContext.End (System.Exception ex) [0x00000] in <filename unknown>:0
at Microsoft.Owin.Host.HttpListener.OwinHttpListener+<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.HttpListener.OwinHttpListener+<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;
}
}
}
答案 3 :(得分:1)
我想我有同样的问题。我描述了它:
我找到了适合我情况的解决方案。我将HttpListener.IgnoreWriteExceptions属性设置为&#39; true&#39;在OWIN配置方法中然后注册中间件。例如:
internal class Startup
{
public void Configuration(IAppBuilder app)
{
object httpListener;
if (app.Properties.TryGetValue(typeof(HttpListener).FullName, out httpListener)
&& httpListener is HttpListener)
{
// HttpListener should not return exceptions that occur
// when sending the response to the client
((HttpListener)httpListener).IgnoreWriteExceptions = true;
}
app.Use<TestOwinMiddleware>();
}
}
我希望这对你有所帮助。