【发布时间】:2022-02-08 01:09:27
【问题描述】:
我完全赞成多线程和异步任务,但放开控制不是我的菜。
我正在从事一个项目,其中一个进程通过 websockets 与多个目标进行通信,并且发送显然应该尽可能快,但必须相互同步。 考虑将视频流同时传输到多个设备。 因此,我不想在目标接收到第一帧之前继续发送下一帧。
当使用 .net WebSockets 时,我已经尝试使用 HttpListner 和 Kestrel 实现(我猜它们或多或少相同),然后 socket.SendAsync 似乎在发送之前接收数据并在本地缓冲它它,在实际发送之前返回 TaskCompleted。这意味着发送任务基本上是瞬间完成的。
我当然“可以”实现一个 ACK 模式,接收者在收到整个数据包时发送一个 ACK,但这本身会减慢进程,我想避免这种情况,因为 is 系统本身已经知道,因为它会尝试连续发送排队的包。
这基本上是负责发送数据的代码,以 2048b 为单位:
Log.Info($"Send {sendBytes.Length}b");
if (socket!.State == WebSocketState.Open)
{
await socket.SendAsync(
sendBuffer,
WebSocketMessageType.Binary,
endOfMessage: true,
cancellationToken: cts
);
}
Log.Info($"Done ");
我会假设这里的 await 实际上会等待传输完成,这是不做的,但它似乎在等待任务完成。
在接收方,这是处理数据,前后有调试响应:
wsClientSession.send("REC " + (String)payloadLength + "b");
ProcessFrame(payload, payloadLength);
wsClientSession.send("ACK " + (String)payloadLength + "b");
发送方的日志显示如下:
- 线程 28 是发送线程,它完成得非常快。它需要发送 6198 个字节并将其分成 4 次传输。这显然是在第一个数据包离开服务器之前完成的。
- 其余线程是调试响应的异步接收者。
- (大小差异是由于数据的加密)
2022-02-07 16:03:34.8887 threadid:28 # Info # Send 6198b to 5d8263c6-909c-47a1-b4d0-57d74d6a4665
2022-02-07 16:03:34.8887 threadid:28 # Info # Send 2048b
2022-02-07 16:03:34.8887 threadid:28 # Info # Done
2022-02-07 16:03:34.8887 threadid:28 # Info # Send 2048b
2022-02-07 16:03:34.8887 threadid:28 # Info # Done
2022-02-07 16:03:34.8887 threadid:28 # Info # Send 2048b
2022-02-07 16:03:34.8887 threadid:28 # Info # Done
2022-02-07 16:03:34.8887 threadid:28 # Info # Send 128b
2022-02-07 16:03:34.8887 threadid:28 # Info # Done
2022-02-07 16:03:34.8887 threadid:28 # Info # Send done to 5d8263c6-909c-47a1-b4d0-57d74d6a4665
2022-02-07 16:03:35.0024 threadid:7 # Info # 5d8263c6-909c-47a1-b4d0-57d74d6a4665 - REC 2030b
2022-02-07 16:03:35.0090 threadid:7 # Info # 5d8263c6-909c-47a1-b4d0-57d74d6a4665 - ACK 2030b
2022-02-07 16:03:35.0090 threadid:17 # Info # 5d8263c6-909c-47a1-b4d0-57d74d6a4665 - REC 2030b
2022-02-07 16:03:35.0260 threadid:33 # Info # 5d8263c6-909c-47a1-b4d0-57d74d6a4665 - ACK 2030b
2022-02-07 16:03:35.0260 threadid:33 # Info # 5d8263c6-909c-47a1-b4d0-57d74d6a4665 - REC 2030b
2022-02-07 16:03:35.0260 threadid:30 # Info # 5d8263c6-909c-47a1-b4d0-57d74d6a4665 - ACK 2030b
2022-02-07 16:03:35.0373 threadid:17 # Info # 5d8263c6-909c-47a1-b4d0-57d74d6a4665 - REC 108b
2022-02-07 16:03:35.0373 threadid:4 # Info # 5d8263c6-909c-47a1-b4d0-57d74d6a4665 - ACK 108b
现在,我对这个 WebSocket 实现的理解全错了吗?是否不可能对数据发送的完整性进行回调/事件或类似的操作?我可以通过其他方式实现这一目标吗? 同步执行这个 true 将是一个解决方案,但我似乎无法强制这样做。
嘎嘎!!
【问题讨论】:
-
你没有放弃控制。 await somethingAsync()` 与
something()没有什么不同,除了调用线程没有浪费等待什么。actually wait for the transmission to complete, which is doesn't do, but it seems to await the task completedness.这是一个自相矛盾的说法。任务是传输。您是否使用了async void方法,只是为了能够使用await?这是一个编码错误,因为无法等待async void方法。它们仅适用于异步事件处理程序 -
Thread 28 is the sending thread, which completes impossibly fast. It needs to send 6198 bytes and chuncks this up in 4 transmissions. It is obviously all done before the first packet has left the server.如果您忘记await实际调用SendAsync的方法,就会发生这种情况。发布足够的代码来重现问题 -
方法本身是这样的: public abstract Task SendAsync(ArraySegment
buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancelToken); ..所以它应该是可以等待的,对吧?那里有一个等待的代码示例,这就是我感到困惑的原因,因为它完成得和它一样快。考虑到有效载荷和接收平台,传输无法在 100uS 内完成,而且这一切都通过 WiFi 进行。我完全是为了学习,所以如果有一个编码错误,那么一切都在我身上。但首先我需要找到它。
标签: .net asynchronous websocket synchronous sendasync