我已经在自托管进程(目前是WinForm主机)中成功运行SignalR . 客户端可以与他们的浏览器连接并完美交互 . 当我需要重新启动游戏领域而不完全杀死主机进程时,问题就出现了 . 在处理了WebApp.Start()返回的IDisposable之后,我重新加载所有业务数据并再次调用WebApp.Start() . 它似乎工作,没有例外或警告冒出来,但无论是否有新的浏览器窗口或选项卡,来自浏览器的客户端连接都会失败 . 我在javascript中启用了SignalR跟踪,并且还通过Fiddler捕获流量 . / negotiate调用有效,但随后对WebSockets的/ connect调用在5秒后超时,然后通过所有其他SignalR回退失败 . 如果我完全杀死主机进程并重新启动它,一切都很好 . 通过每次杀死整个过程手动重启是不可行的 . 我打开了服务器端日志记录,这是我看到的行为:
SignalR.Transports.TransportHeartBeat Information: 0 : Connection a9f279c9-9dcb-4cc2-806b-dd95e96561b4 is New.
SignalR.Transports.TransportHeartBeat Verbose: 0 : KeepAlive(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.TransportHeartBeat Verbose: 0 : KeepAlive(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.TransportHeartBeat Verbose: 0 : KeepAlive(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.TransportHeartBeat Verbose: 0 : KeepAlive(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.TransportHeartBeat Verbose: 0 : KeepAlive(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.TransportHeartBeat Verbose: 0 : KeepAlive(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.TransportHeartBeat Verbose: 0 : KeepAlive(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.TransportHeartBeat Verbose: 0 : KeepAlive(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.TransportHeartBeat Verbose: 0 : KeepAlive(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.TransportHeartBeat Information: 0 : Dispose(). Closing all connections
SignalR.Transports.WebSocketTransport Error: 0 : OnError(a9f279c9-9dcb-4cc2-806b-dd95e96561b4, System.Net.WebSockets.WebSocketException (0x80004005): An internal WebSocket error occurred. Please see the innerException, if present, for more details. ---> System.Net.HttpListenerException (0x80004005): The I/O operation has been aborted because of either a thread exit or an application request
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Net.WebSockets.WebSocketHttpListenerDuplexStream.<ReadAsyncCore>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
at System.Net.WebSockets.WebSocketBase.WebSocketOperation.<Process>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Net.WebSockets.WebSocketBase.<ReceiveAsyncCore>d__1.MoveNext()
at System.Net.WebSockets.WebSocketBase.ThrowIfConvertibleException(String methodName, Exception exception, CancellationToken cancellationToken, Boolean aborted)
at System.Net.WebSockets.WebSocketBase.<ReceiveAsyncCore>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.SignalR.WebSockets.WebSocketMessageReader.<ReadMessageAsync>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.SignalR.WebSockets.WebSocketHandler.<ProcessWebSocketRequestAsync>d__e.MoveNext())
SignalR.Transports.WebSocketTransport Information: 0 : End(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Information: 0 : CloseSocket(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Verbose: 0 : Cancel(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Verbose: 0 : DrainWrites(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Information: 0 : CompleteRequest (a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.TransportHeartBeat Verbose: 0 : Connection a9f279c9-9dcb-4cc2-806b-dd95e96561b4 exists. Closing previous connection.
SignalR.Transports.TransportHeartBeat Verbose: 0 : Connection a9f279c9-9dcb-4cc2-806b-dd95e96561b4 exists. Closing previous connection.
SignalR.Transports.WebSocketTransport Information: 0 : End(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Verbose: 0 : Cancel(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Information: 0 : CloseSocket(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Verbose: 0 : DrainWrites(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Information: 0 : CompleteRequest (a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Information: 0 : CloseSocket(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.TransportHeartBeat Verbose: 0 : Connection a9f279c9-9dcb-4cc2-806b-dd95e96561b4 exists. Closing previous connection.
SignalR.Transports.WebSocketTransport Information: 0 : End(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Verbose: 0 : Cancel(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Verbose: 0 : DrainWrites(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Information: 0 : CompleteRequest (a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.TransportHeartBeat Information: 0 : Connection 263abf1d-aa32-41aa-af16-d64c530cd001 is New.
SignalR.Transports.WebSocketTransport Information: 0 : CloseSocket(263abf1d-aa32-41aa-af16-d64c530cd001)
SignalR.Transports.TransportHeartBeat Verbose: 0 : Connection 263abf1d-aa32-41aa-af16-d64c530cd001 exists. Closing previous connection.
SignalR.Transports.WebSocketTransport Information: 0 : End(263abf1d-aa32-41aa-af16-d64c530cd001)
SignalR.Transports.WebSocketTransport Verbose: 0 : Cancel(263abf1d-aa32-41aa-af16-d64c530cd001)
SignalR.Transports.WebSocketTransport Verbose: 0 : DrainWrites(263abf1d-aa32-41aa-af16-d64c530cd001)
SignalR.Transports.WebSocketTransport Information: 0 : CompleteRequest (263abf1d-aa32-41aa-af16-d64c530cd001)
SignalR.Transports.TransportHeartBeat Verbose: 0 : Connection 263abf1d-aa32-41aa-af16-d64c530cd001 exists. Closing previous connection.
SignalR.Transports.ServerSentEventsTransport Information: 0 : End(263abf1d-aa32-41aa-af16-d64c530cd001)
SignalR.Transports.ServerSentEventsTransport Verbose: 0 : Cancel(263abf1d-aa32-41aa-af16-d64c530cd001)
SignalR.Transports.ServerSentEventsTransport Verbose: 0 : DrainWrites(263abf1d-aa32-41aa-af16-d64c530cd001)
SignalR.Transports.ServerSentEventsTransport Information: 0 : CompleteRequest (263abf1d-aa32-41aa-af16-d64c530cd001)
SignalR.Transports.WebSocketTransport Information: 0 : CloseSocket(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.TransportHeartBeat Verbose: 0 : Connection a9f279c9-9dcb-4cc2-806b-dd95e96561b4 exists. Closing previous connection.
SignalR.Transports.WebSocketTransport Information: 0 : End(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Verbose: 0 : Cancel(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Verbose: 0 : DrainWrites(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Information: 0 : CompleteRequest (a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Information: 0 : CloseSocket(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.TransportHeartBeat Verbose: 0 : Connection a9f279c9-9dcb-4cc2-806b-dd95e96561b4 exists. Closing previous connection.
SignalR.Transports.WebSocketTransport Information: 0 : End(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
注意在处理过程中会发生错误,然后它会进入这种状态,它会永久地为现有连接和新连接重复该模式 .
任何帮助赞赏 .
Update: 有人请求共享重启的代码 . 它's basically a long running process, so at the core of my engine I'有一个循环循环,直到我告诉它停止 .
protected void MainLoop()
{
//load all data from the db
using (Microsoft.Owin.Hosting.WebApp.Start(dbRealm.SignalRUrl))
{
while (!this.stopping)
{
try
{
this.ProcessFrame();
}
catch (Exception exc)
{
//todo: log error
throw exc;
}
Thread.Sleep(1); //yield
}
}
//cleanup/shut down stuff
}
这是通过以下代码在它自己的线程上运行:
public void Start()
{
//threading/message stuffs
if (!this.running)
{
this.running = true;
ThreadStart ts = new ThreadStart(this.MainLoop);
this.mainThread = new Thread(ts);
this.mainThread.Start();
}
else
{
//message
}
}
这是我的Startup类:
class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR("/signalr", new HubConfiguration { EnableDetailedErrors = true, Resolver = new DefaultDependencyResolver() });
app.RunSignalR();
}
}
Update #2: 我可能在OP中不够清楚 . 除了使用Fiddler记录流量之外,我还在客户端启用了SignalR跟踪 . 这是浏览器中的输出:
[08:03:37] SignalR: Auto detected cross domain url.
[08:03:37] SignalR: Client subscribed to hub 'webmudhub'.
[08:03:37] SignalR: Negotiating with 'http://localhost:8080/negotiate?clientProtocol=1.5&connectionData=%5B%7B%22name%22%3A%22webmudhub%22%7D%5D'.
[08:03:37] SignalR: webSockets transport starting.
[08:03:37] SignalR: Connecting to websocket endpoint 'ws://localhost:8080/connect?transport=webSockets&clientProtocol=1.5&connectionToken=AQAAANCMnd8BFdERjHoAwE%2FCl%2BsBAAAAecyNVO0bfE6%2BclQisGhh8QAAAAACAAAAAAAQZgAAAAEAACAAAACo51RwDaqYAC1N2%2FkMiQkuFhbVLfrH%2FfJEfdz9TV9F7AAAAAAOgAAAAAIAACAAAADrjqx8pyEMjZ%2BCkUHeZJcdwXH2LaSe1Qlh9XA7fo84MTAAAAB7mClxFPbknblDmZ8a14Thoa6FcLY7%2BS6fJpAXpeO8AaB8y5n4iCD6DotnQH07UDNAAAAA9eV4FLk1hr83h8NDy%2BWwKvGF%2FGn%2F00AOmn%2BMEfvcS5fa2xO%2F0Vd1sjd6TpJdTpePmakv1uOjTekP6FFYXVTU7g%3D%3D&connectionData=%5B%7B%22name%22%3A%22webmudhub%22%7D%5D&tid=0'.
[08:03:37] SignalR: Websocket opened.
[08:03:42] SignalR: webSockets transport timed out when trying to connect.
[08:03:42] SignalR: Closing the Websocket.
[08:03:42] SignalR: webSockets transport failed to connect. Attempting to fall back.
[08:03:42] SignalR: serverSentEvents transport starting.
[08:03:42] SignalR: Attempting to connect to SSE endpoint 'http://localhost:8080/connect?transport=serverSentEvents&clientProtocol=1.5…XVTU7g%3D%3D&connectionData=%5B%7B%22name%22%3A%22webmudhub%22%7D%5D&tid=3'.
[08:03:42] SignalR: EventSource connected.
[08:03:47] SignalR: serverSentEvents transport timed out when trying to connect.
[08:03:47] SignalR: EventSource calling close().
[08:03:47] SignalR: serverSentEvents transport failed to connect. Attempting to fall back.
[08:03:47] SignalR: longPolling transport starting.
[08:03:48] SignalR: Opening long polling request to 'http://localhost:8080/connect?transport=longPolling&clientProtocol=1.5&conn…kP6FFYXVTU7g%3D%3D&connectionData=%5B%7B%22name%22%3A%22webmudhub%22%7D%5D'.
[08:03:52] SignalR: longPolling transport timed out when trying to connect.
[08:03:52] SignalR: Aborted xhr request.
[08:03:52] SignalR: longPolling transport failed to connect. Attempting to fall back.
[08:03:52] SignalR: Fallback transports exhausted.
[08:03:52] SignalR: Stopping connection.
[08:03:52] SignalR: Fired ajax abort async = true.
请注意,在第一次处理WebApp.Start()之后第二次调用WebApp.Start()后,这是在新的浏览器连接上的 brand new connection 上 . 感觉可能没有在SignalR中正确处理某些东西,导致某种残余物导致问题 .
这是另一个服务器端日志 . 我启动了服务器,停止了它(处理SignalR),然后重新启动它(进行新的WebApp.Start()调用) . 它应该在这一点上接受新的连接 . 相反,我看到了这个:
SignalR.Transports.TransportHeartBeat Information: 0 : Connection 92c4d8da-aeb5-4056-b274-625a83a366b1 is New.
SignalR.Transports.WebSocketTransport Information: 0 : CloseSocket(92c4d8da-aeb5-4056-b274-625a83a366b1)
SignalR.Transports.TransportHeartBeat Verbose: 0 : 92c4d8da-aeb5-4056-b274-625a83a366b1 is dead
SignalR.Transports.TransportHeartBeat Verbose: 0 : Connection 92c4d8da-aeb5-4056-b274-625a83a366b1 exists. Closing previous connection.
SignalR.Transports.WebSocketTransport Information: 0 : End(92c4d8da-aeb5-4056-b274-625a83a366b1)
SignalR.Transports.WebSocketTransport Verbose: 0 : Cancel(92c4d8da-aeb5-4056-b274-625a83a366b1)
SignalR.Transports.WebSocketTransport Verbose: 0 : DrainWrites(92c4d8da-aeb5-4056-b274-625a83a366b1)
SignalR.Transports.WebSocketTransport Information: 0 : CompleteRequest (92c4d8da-aeb5-4056-b274-625a83a366b1)
SignalR.Transports.TransportHeartBeat Verbose: 0 : KeepAlive(92c4d8da-aeb5-4056-b274-625a83a366b1)
SignalR.Transports.TransportHeartBeat Verbose: 0 : Connection 92c4d8da-aeb5-4056-b274-625a83a366b1 exists. Closing previous connection.
SignalR.Transports.ServerSentEventsTransport Information: 0 : End(92c4d8da-aeb5-4056-b274-625a83a366b1)
SignalR.Transports.ServerSentEventsTransport Verbose: 0 : Cancel(92c4d8da-aeb5-4056-b274-625a83a366b1)
SignalR.Transports.ServerSentEventsTransport Verbose: 0 : DrainWrites(92c4d8da-aeb5-4056-b274-625a83a366b1)
SignalR.Transports.ServerSentEventsTransport Information: 0 : CompleteRequest (92c4d8da-aeb5-4056-b274-625a83a366b1)
SignalR.Transports.TransportHeartBeat Verbose: 0 : KeepAlive(92c4d8da-aeb5-4056-b274-625a83a366b1)
SignalR.Transports.TransportHeartBeat Verbose: 0 : KeepAlive(92c4d8da-aeb5-4056-b274-625a83a366b1)
SignalR.Transports.TransportHeartBeat Verbose: 0 : KeepAlive(92c4d8da-aeb5-4056-b274-625a83a366b1)
我们再一次看到新的连接,然后5秒后由于某种原因调用CloseSocket(),也许是因为它认为它已经死了?
我基本上试图遵循这种模式:https://weblog.west-wind.com/posts/2013/Sep/04/SelfHosting-SignalR-in-a-Windows-Service
我知道这是一个Windows服务,我的是在WinForm应用程序中托管,所以也许这就是区别?我想知道Windows服务是否在每个启动服务的请求上创建一个新的AppDomain . 正如我所说,如果我完全杀死WinForm应用程序并重新启动它,一切都会再次运行 .
在我看来,我应该能够Dispose of SignalR,然后通过另一次调用WebApp.Start()来启动它,但第二次调用WebApp.Start不会出错,但它也没有正确接受任何新的传入连接 . 他们超时了 . 这显然是我的猜想,但也许是SignalR中的单例模式或类似模式在IDisposable实现中没有被正确处理?我选择WinForms来在开发期间轻松记录/通知每个领域各自的WinForm主机,因为我将在每台Windows服务器上运行多个实例(每个实例在其自己的端口上都有自己的SignalR实例) .