我正在尝试创建一个ASP.NET Core Web服务器,它通过websockets与客户端通信。我发现我的服务器可以毫无问题地连接到客户端并从客户端接收数据,但无法将数据发送回客户端。
我正在使用我在Python中开发的websocket客户端测试服务器,这允许我逐步完成代码,而似乎发生的事情是,在我的服务器发送数据之后,Python端的websocket使用的streamreader遇到了EOF并关闭,导致websocket本身关闭,错误代码为1006.我知道客户端没有问题,因为它与基于.NET Framework(我正在迁移的)的另一个版本的服务器相关。
我正在使用Microsoft.AspNetCore.WebSockets.Server
v0.1.0。以下是我的project.json
:
{
"dependencies": {
"<<Company>>.Communications.<<Product>>Usb": "0.4.7",
"<<Company>>.<<Product>>Web.Core": {
"target": "project"
},
"<<Company>>.<<Product>>WebComponentPackage": "0.4.4",
"Common.Logging": "3.4.0-Beta2",
"Microsoft.AspNetCore.Diagnostics": "1.0.0",
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
"Microsoft.AspNetCore.StaticFiles": "1.0.0",
"Microsoft.AspNetCore.WebSockets.Server": "0.1.0",
"Microsoft.Composition": "1.0.30",
"Microsoft.Extensions.DependencyModel": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0",
"Microsoft.NETCore.App": {
"version": "1.0.1",
"type": "platform"
},
"System.Runtime.Loader": "4.0.0",
"Thrower": "3.0.4"
},
"tools": {
"Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"
},
"frameworks": {
"netcoreapp1.0": {
"imports": [
"dotnet5.6",
"portable-net45+win8"
]
}
},
"buildOptions": {
"emitEntryPoint": true,
"preserveCompilationContext": true
},
"runtimeOptions": {
"configProperties": {
"System.GC.Server": true
}
},
"publishOptions": {
"include": [
"wwwroot",
"web.config"
]
},
"scripts": {
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
}
}
在Startup.cs
中,我定义了我的websocket中间件:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
...
var websocketManager = app.ApplicationServices.GetService<WebSocketManager>();
app.UseWebSockets();
app.Use(websocketManager.Acceptor);
}
我的WebSocketManager
类处理websocket请求:
public async Task Acceptor(HttpContext context, Func<Task> tasks)
{
if (!context.WebSockets.IsWebSocketRequest)
{
return;
}
IWebSocketBehaviour wsBehaviour;
var socket = await context.WebSockets.AcceptWebSocketAsync();
Debug.Assert(socket.State == WebSocketState.Open);
if (!this.TryGetWebSocketBehaviour(context, socket, out wsBehaviour))
{
socket.Dispose();
return;
}
this.websocketBehaviours.Add(wsBehaviour);
await wsBehaviour.Run();
this.websocketBehaviours.Remove(wsBehaviour);
}
我的抽象WebSocketBehaviour
类定义Run
如下:
public async Task Run()
{
try
{
var buffer = new ArraySegment<byte>(new byte[BufferSize]);
this.OnOpen();
while (this.socket.State == WebSocketState.Open)
{
WebSocketReceiveResult receivedMessage;
try
{
receivedMessage = await this.socket.ReceiveAsync(buffer, Token);
}
catch (IOException)
{
await Task.Delay(10);
continue;
}
if (receivedMessage.MessageType == WebSocketMessageType.Text)
{
var data = buffer.Array.TakeWhile(x => x != 0).ToArray();
var request = Encoding.UTF8.GetString(data, 0, data.Length);
this.OnMessage(request);
}
}
if (this.socket.CloseStatus.HasValue && (this.socket.CloseStatus.Value != WebSocketCloseStatus.NormalClosure))
{
this.OnError(this.socket.CloseStatus.Value, this.socket.CloseStatusDescription);
}
await this.socket.CloseAsync(this.socket.CloseStatus ?? WebSocketCloseStatus.Empty,
this.socket.CloseStatusDescription, Token);
this.OnClose();
}
finally
{
this.socket.Dispose();
}
}
最后Send
的定义如下:
protected async Task Send(string response)
{
Raise.InvalidOperationException.If(this.socket.State != WebSocketState.Open);
var buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(response));
await this.socket.SendAsync(buffer, WebSocketMessageType.Text, true, Token);
}
在一个场景中,我使用我的websocket客户端发送信息请求,该信息应该提示服务器的响应。我观察到以下一系列行为:
客户端发送{"op":"get", "path":"..."}
形式的JSON请求。我在客户端看到以下日志:
2016-10-06 11:45:01,805 [DEBUG ] asyncio - Using selector: SelectSelector
2016-10-06 11:45:01,806 [DEBUG ] Rx - CurrentThreadScheduler.schedule(state=None)
2016-10-06 11:45:01,807 [DEBUG ] Rx - CurrentThreadScheduler.schedule(state=None)
2016-10-06 11:45:01,807 [DEBUG ] Rx - CurrentThreadScheduler.schedule(state=None)
2016-10-06 11:45:01,807 [DEBUG ] Rx - CurrentThreadScheduler.schedule(state=None)
2016-10-06 11:45:01,808 [DEBUG ] Rx - CurrentThreadScheduler.schedule(state=None)
2016-10-06 11:45:01,808 [DEBUG ] Rx - CurrentThreadScheduler.schedule(state=None)
2016-10-06 11:45:01,808 [DEBUG ] Rx - CurrentThreadScheduler.schedule(state=None)
2016-10-06 11:45:01,812 [INFO ] <<Product>>.comms - Establishing connection to <<Product>> Web Service @ 127.0.0.1:5000
2016-10-06 11:45:01,815 [DEBUG ] asyncio - connect <socket.socket fd=860, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6> to ('127.0.0.1', 5000)
2016-10-06 11:45:01,818 [DEBUG ] asyncio - poll took 0.000 ms: 1 events
2016-10-06 11:45:01,825 [DEBUG ] asyncio - <socket.socket fd=860, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6, laddr=('127.0.0.1', 60824), raddr=('127.0.0.1', 5000)> connected to 127.0.0.1:5000: (<_SelectorSocketTransport fd=860 read=polling write=<idle, bufsize=0>>, <websockets.client.WebSocketClientProtocol object at 0x037B5EF0>)
2016-10-06 11:45:02,031 [DEBUG ] asyncio - poll took 203.000 ms: 1 events
2016-10-06 11:45:02,035 [DEBUG ] <<Product>>.comms - Connected using websocket address: ws://127.0.0.1:5000/
2016-10-06 11:45:02,035 [DEBUG ] <<Product>>.component - Using read handler
2016-10-06 11:45:02,037 [DEBUG ] <<Product>>.comms - Sending request: {"op": "get", "path": "<<Product>>.relays[0].enabled"}
2016-10-06 11:45:02,040 [DEBUG ] Rx - CurrentThreadScheduler.schedule(state=None)
2016-10-06 11:45:02,041 [DEBUG ] <<Product>>.comms - Listening for responses
2016-10-06 11:45:02,043 [DEBUG ] websockets.protocol - client >> Frame(fin=True, opcode=1, data=b'{"op": "get", "path": "<<Product>>.relays[0].enabled"}')
在服务器端,我看到:
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://127.0.0.1:5000/
服务器生成响应:{"timestamp":1475754679475,"status":"success","path":"$.relays[0].enabled","module":"<<product>>.relayController","data":[false]}
。
服务器将此响应编码为字节序列并执行await this.socket.SendAsync(buffer, WebSocketMessageType.Text, true, Token);
在客户端,我看到了这些额外的日志:
2016-10-06 11:56:53,155 [INFO ] asyncio - poll took 333764.000 ms: 1 events
2016-10-06 11:56:53,156 [DEBUG ] asyncio - <_SelectorSocketTransport fd=820 read=polling write=<idle, bufsize=0>> received EOF
2016-10-06 11:56:53,157 [INFO ] websockets.protocol - Failing the WebSocket connection: 1006
在服务器端,我通常看不到其他日志,但偶尔当我尝试这个时,我得到以下异常日志:
Microsoft.AspNetCore.Server.Kestrel.Internal.Networking.UvException: Error -4077
ECONNRESET connection reset by peer
info: Microsoft.AspNetCore.Server.Kestrel[14]
Connection id "0HKVDQUJUEKU0" communication error
Microsoft.AspNetCore.Server.Kestrel.Internal.Networking.UvException: Error -4081
ECANCELED operation canceled
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[0]
An unhandled exception has occurred while executing the request
System.Threading.Tasks.TaskCanceledException: A task was canceled.
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNot
ification(Task task)
at Microsoft.AspNetCore.WebSockets.Protocol.CommonWebSocket.<EnsureDataAvaila
bleOrReadAsync>d__38.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.HandleNonSuccessAndDebuggerNot
ification(Task task)
at Microsoft.AspNetCore.WebSockets.Protocol.CommonWebSocket.<ReadNextFrameAsy
nc>d__37.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.HandleNonSuccessAndDebuggerNot
ification(Task task)
at Microsoft.AspNetCore.WebSockets.Protocol.CommonWebSocket.<ReceiveAsync>d__
36.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.HandleNonSuccessAndDebuggerNot
ification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at <<Company>>.<<Product>>Web.ServiceAdapters.WebSockets.WebSocketBehaviour.<Run>d_
_4.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.HandleNonSuccessAndDebuggerNot
ification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at <<Company>>.<<Product>>Web.ServiceAdapters.WebSockets.WebSocketManager.<Acceptor
>d__4.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.HandleNonSuccessAndDebuggerNot
ification(Task task)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.<Invoke>
d__6.MoveNext()
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[0]
An unhandled exception has occurred while executing the request
System.Threading.Tasks.TaskCanceledException: A task was canceled.
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNot
ification(Task task)
at Microsoft.AspNetCore.WebSockets.Protocol.CommonWebSocket.<EnsureDataAvaila
bleOrReadAsync>d__38.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.HandleNonSuccessAndDebuggerNot
ification(Task task)
at Microsoft.AspNetCore.WebSockets.Protocol.CommonWebSocket.<ReadNextFrameAsy
nc>d__37.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.HandleNonSuccessAndDebuggerNot
ification(Task task)
at Microsoft.AspNetCore.WebSockets.Protocol.CommonWebSocket.<ReceiveAsync>d__
36.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.HandleNonSuccessAndDebuggerNot
ification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at <<Company>>.<<Product>>Web.ServiceAdapters.WebSockets.WebSocketBehaviour.<Run>d_
_4.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.HandleNonSuccessAndDebuggerNot
ification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at <<Company>>.<<Product>>Web.ServiceAdapters.WebSockets.WebSocketManager.<Acceptor
>d__4.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.HandleNonSuccessAndDebuggerNot
ification(Task task)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.<Invoke>
d__6.MoveNext()
warn: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[0]
The response has already started, the error page middleware will not be ex
ecuted.
warn: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[0]
The response has already started, the error page middleware will not be ex
ecuted.
fail: Microsoft.AspNetCore.Server.Kestrel[13]
Connection id "0HKVDQUJUEKU1": An unhandled exception was thrown by the ap
plication.
System.Threading.Tasks.TaskCanceledException: A task was canceled.
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNot
ification(Task task)
at Microsoft.AspNetCore.WebSockets.Protocol.CommonWebSocket.<EnsureDataAvaila
bleOrReadAsync>d__38.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.HandleNonSuccessAndDebuggerNot
ification(Task task)
at Microsoft.AspNetCore.WebSockets.Protocol.CommonWebSocket.<ReadNextFrameAsy
nc>d__37.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.HandleNonSuccessAndDebuggerNot
ification(Task task)
at Microsoft.AspNetCore.WebSockets.Protocol.CommonWebSocket.<ReceiveAsync>d__
36.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.HandleNonSuccessAndDebuggerNot
ification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at <<Company>>.<<Product>>Web.ServiceAdapters.WebSockets.WebSocketBehaviour.<Run>d_
_4.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.HandleNonSuccessAndDebuggerNot
ification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at <<Company>>.<<Product>>Web.ServiceAdapters.WebSockets.WebSocketManager.<Acceptor
>d__4.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.HandleNonSuccessAndDebuggerNot
ification(Task task)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.<Invoke>
d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.<Invoke>
d__6.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.HandleNonSuccessAndDebuggerNot
ification(Task task)
at Microsoft.AspNetCore.Hosting.Internal.RequestServicesContainerMiddleware.<
Invoke>d__3.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.HandleNonSuccessAndDebuggerNot
ification(Task task)
at Microsoft.AspNetCore.Server.Kestrel.Internal.Http.Frame`1.<RequestProcessi
ngAsync>d__2.MoveNext()
fail: Microsoft.AspNetCore.Server.Kestrel[13]
Connection id "0HKVDQUJUEKU0": An unhandled exception was thrown by the ap
plication.
System.Threading.Tasks.TaskCanceledException: A task was canceled.
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNot
ification(Task task)
at Microsoft.AspNetCore.WebSockets.Protocol.CommonWebSocket.<EnsureDataAvaila
bleOrReadAsync>d__38.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.HandleNonSuccessAndDebuggerNot
ification(Task task)
at Microsoft.AspNetCore.WebSockets.Protocol.CommonWebSocket.<ReadNextFrameAsy
nc>d__37.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.HandleNonSuccessAndDebuggerNot
ification(Task task)
at Microsoft.AspNetCore.WebSockets.Protocol.CommonWebSocket.<ReceiveAsync>d__
36.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.HandleNonSuccessAndDebuggerNot
ification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at <<Company>>.<<Product>>Web.ServiceAdapters.WebSockets.WebSocketBehaviour.<Run>d_
_4.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.HandleNonSuccessAndDebuggerNot
ification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at <<Company>>.<<Product>>Web.ServiceAdapters.WebSockets.WebSocketManager.<Acceptor
>d__4.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.HandleNonSuccessAndDebuggerNot
ification(Task task)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.<Invoke>
d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.<Invoke>
d__6.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.HandleNonSuccessAndDebuggerNot
ification(Task task)
at Microsoft.AspNetCore.Hosting.Internal.RequestServicesContainerMiddleware.<
Invoke>d__3.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.HandleNonSuccessAndDebuggerNot
ification(Task task)
at Microsoft.AspNetCore.Server.Kestrel.Internal.Http.Frame`1.<RequestProcessi
ngAsync>d__2.MoveNext()
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 2630.6342ms 101
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 11495.3447ms 101