我正在测试当客户端能够足够快地从服务器端处理数据时.NET WebSockets如何工作。为此,我编写了一个将数据连续发送到WebSocket的应用程序,但在接收循环中包含了一个人工延迟。正如预期的那样,一旦TCP窗口和其他缓冲区填满,SendAsync调用开始需要很长时间才能返回。但几分钟后,SendAsync抛出了其中一个异常:
System.Net.HttpListenerException:设备无法识别该命令 System.Net.HttpListenerException:由于线程退出或应用程序请求,I / O操作已中止。
奇怪的是,这只发生在某些消息大小和特定时间。当允许客户端读取所有不受限制的数据时,连接是稳定的。此外,当客户端被完全阻止而根本不读取时,连接保持打开状态。
通过Wireshark检查数据流显示,当客户端的TCP窗口耗尽时,服务器正在重置TCP连接。
我试图按照这个答案(reporting)但没有成功。调整WebSocket保持活动间隔没有任何影响。另外,我知道最终的应用程序需要能够优雅地处理意外的断开连接,但如果可以避免它们,我不希望它们发生。
有没有人遇到过这个?我可以做一些超时调整吗?运行此操作应该会在一分钟到一半到三分钟之间产生错误:
class Program
{
static void Main(string[] args)
{
System.Net.ServicePointManager.MaxServicePointIdleTime = Int32.MaxValue; // has no effect
HttpListener httpListener = new HttpListener();
httpListener.Prefixes.Add("http://*/ws/");
Listen(httpListener);
Thread.Sleep(500);
Receive("ws://localhost/ws/");
Console.WriteLine("running...");
Console.ReadKey();
}
private static async void Listen(HttpListener listener)
{
listener.Start();
while (true)
{
HttpListenerContext ctx = await listener.GetContextAsync();
if (!ctx.Request.IsWebSocketRequest)
{
ctx.Response.StatusCode = (int)HttpStatusCode.NotImplemented;
ctx.Response.Close();
return;
}
Send(ctx);
}
}
private static async void Send(HttpListenerContext ctx)
{
TimeSpan keepAliveInterval = TimeSpan.FromSeconds(5); // tweaking has no effect
HttpListenerWebSocketContext wsCtx = await ctx.AcceptWebSocketAsync(null, keepAliveInterval);
WebSocket webSocket = wsCtx.WebSocket;
byte[] buffer = new byte[100];
while (true)
{
await webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Binary, true, CancellationToken.None);
}
}
private static async void Receive(string serverAddress)
{
ClientWebSocket webSocket = new ClientWebSocket();
webSocket.Options.KeepAliveInterval = TimeSpan.FromSeconds(5); // tweaking has no effect
await webSocket.ConnectAsync(new Uri(serverAddress), CancellationToken.None);
byte[] receiveBuffer = new byte[10000];
while (true)
{
await Task.Delay(10); // simulate a slow client
var message = await webSocket.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), CancellationToken.None);
if (message.CloseStatus.HasValue)
break;
}
}
答案 0 :(得分:2)
我不是.NET开发人员,但据我在websocket主题中看到这些问题而且我个人认为,这些可能是原因:
onError
和onClose
方法以查明原因)ping
和pong
数据包。正如您所说,您的错误通常会在一定时间内发生,1和2必须帮助您。再次抱歉,如果我无法为您提供代码,但我在java中遇到了同样的问题,我发现这些是必须设置的设置才能使用websockets。搜索如何在客户端和服务器实现中设置这些,并且在此之后一定要好。
答案 1 :(得分:1)
显然,我正在点击HTTP.SYS低速连接攻击对策,如KB 3137046(https://support.microsoft.com/en-us/help/3137046/http-sys-forcibly-disconnects-http-bindings-for-wcf-self-hosted-servic)中粗略描述的那样:
默认情况下,Http.sys将任何低于150字节/秒的速率视为潜在的低速连接攻击,它会丢弃TCP连接以释放资源。
当HTTP.SYS执行此操作时,日志中有一个跟踪条目%windir%\ System32 \ LogFiles \ HTTPERR
从代码中关闭它很简单:
httpListener.TimeoutManager.MinSendBytesPerSecond = UInt32.MaxValue;