我遇到了一个问题,可以通过以下方式进行复制(您需要IIS8,因此必须在Windows 8+或Windows Server 2012 R2 +上):
在IIS管理器中创建一个新网站,在端口8881上说TestWs,指向一个新文件夹,比如C:\ temp \ testws,并在其中添加以下Web.config文件
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation targetFramework="4.5"/>
<httpRuntime targetFramework="4.5"/>
</system.web>
</configuration>
现在将以下WsHandler.ashx文件添加到同一文件夹
中<%@ WebHandler Language="C#" Class="WsHandler" %>
using System;
using System.Threading;
using System.Web;
public class WsHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.AcceptWebSocketRequest(async webSocketContext =>
{
while (true)
{
await webSocketContext.WebSocket.ReceiveAsync(new ArraySegment<byte>(new byte[1024]), CancellationToken.None);
}
});
}
public bool IsReusable { get { return true; } }
}
然后在浏览器的开发人员工具栏中创建一个websocket,如此
var ws = new WebSocket("ws://localhost:8881/wshandler.ashx");
ws.onclose = function() { console.log('closed'); };
在任务管理器中,您将看到此应用程序有一个w3wp.exe进程,如果您终止它,则客户端会引发onclose事件并打印关闭的文本。
但是,如果您创建一个如上所述的websocket并转到IIS管理器并回收应用程序池,那么websocket将不会关闭,现在将有两个w3wp.exe进程。
关闭Web套接字ws.close();
或刷新浏览器将导致原始w3wp.exe进程关闭。
似乎存在打开的websocket导致IIS无法正确回收应用程序池。
任何人都可以找出我的代码中要更改的内容或IIS中要更改的内容以使其生效吗?
答案 0 :(得分:5)
据我所知,当WebSocket打开时,IIS不会拆除应用程序域,因此您会看到此行为。
我能建议的最好的是你做一些跨进程信令来强制关闭旧实例。您可以使用EventWaitHandle:
来实现此目的在您的网络应用程序中创建一个名为EventWaitHandle,并在启动时发出信号。
在单独的线程上,等待等待句柄
发出信号后,请致电HostingEnvironment.InitiateShutdown以强制关闭所有正在运行的旧实例。
答案 1 :(得分:3)
尝试设置&#34;关机时间限制&#34;到1秒(应用程序池&gt;高级设置&gt;处理模型)[PS:我没有IIS8。我正在检查IIS7中的属性。]
此属性定义工作进程完成处理请求和关闭的时间。如果工作进程超过关闭时间限制,则终止。
我可以看到IIS7中的默认值是90秒。如果IIS8中的值相同,那么它可能会给早期的工作流程花费那么多时间来完成它的工作。 90秒(1.5分钟)后,它将终止该过程,您的Web套接字将关闭。如果将其更改为1秒,它将终止早期的工作进程几乎立即终止(一旦您回收应用程序池),您将获得预期的行为。
答案 2 :(得分:1)
由于我遇到同样的问题,这是我想出的解决方案:
在你的IHttpHandler中你应该有一个继承IStopListeningRegisteredObject的静态对象。然后使用HostingEnvironment.RegisterObject(this)在应用程序池重新计算时得到通知(通过StopListening)。
你还需要一个CancellationTokenSource(也是静态的),你将在ReceiveAsync中交出。在StopListening()中,您可以使用CancellationTokenSource的Cancel()来结束等待。然后捕获OperationCanceledException并在套接字上调用Abort()。
在取消()或App-Pool仍然等待之后,不要忘记Dispose()。