如何解决如何使用Kestrel ConnectionHandler处理传入的TCP消息?
我想为我的.NET Core项目创建一个TCP侦听器。我正在使用Kestrel,并通过
为此配置了新的ConnectionHandler
kestrelServerOptions.ListenLocalhost(5000,builder =>
{
builder.UseConnectionHandler<MyTCPConnectionHandler>();
});
所以我到目前为止是
internal class MyTCPConnectionHandler : ConnectionHandler
{
public override async Task OnConnectedAsync(ConnectionContext connection)
{
IDuplexPipe pipe = connection.Transport;
PipeReader pipeReader = pipe.Input;
while (true)
{
ReadResult readResult = await pipeReader.ReadAsync();
ReadOnlySequence<byte> readResultBuffer = readResult.Buffer;
foreach (ReadOnlyMemory<byte> segment in readResultBuffer)
{
// read the current message
string messageSegment = Encoding.UTF8.GetString(segment.Span);
// send back an echo
await pipe.Output.WriteAsync(segment);
}
if (readResult.IsCompleted)
{
break;
}
pipeReader.AdvanceTo(readResultBuffer.Start,readResultBuffer.End);
}
}
}
从TCP客户端向服务器应用程序发送消息时,代码可以正常工作。 await pipe.Output.WriteAsync(segment);
行现在的作用像是回声。
出现一些问题
- 我应将什么响应发送回客户端,以免超时?
- 我应何时发送回信?当
readResult.IsCompleted
返回true时? - 如何更改代码以获取客户端发送的整个消息?我应该将每个
messageSegment
存储在List<string>
中,并在readResult.IsCompleted
返回true时将其连接到单个字符串吗?
解决方法
- 这完全取决于协议;在许多情况下,您什么都不做就可以了;在其他情况下,如果您只想说“我还在这里”,则会发送特定的“ ping” /“ pong”帧
- “何时”完全取决于协议;等待
SwitchRow
意味着您正在等待入站套接字被标记为已关闭,这意味着您将不会发送任何内容,直到客户端关闭其出站套接字为止;对于单发协议,这可能很好;但在大多数情况下,您需要查找一个入站框架,然后回复该框架(并重复) - 听起来您确实确实在写一个通道,即客户端仅向服务器发送一件事,然后:服务器仅向客户端发送一件事; 在这种情况下,您将执行以下操作:
readResult.IsCompleted
至:
我应该将每个
while (true) { var readResult = await pipeReader.ReadAsync(); if (readResult.IsCompleted) { // TODO: not shown; process readResult.Buffer // tell the pipe that we consumed everything,and exit pipeReader.AdvanceTo(readResultBuffer.End,readResultBuffer.End); break; } else { // wait for the client to close their outbound; tell // the pipe that we couldn't consume anything pipeReader.AdvanceTo(readResultBuffer.Start,readResultBuffer.End); }
存储在messageSegment
中,并在需要时将其连接到单个字符串中吗
这里首先要考虑的是,每个缓冲区段不一定包含确切数量的字符。由于您使用的是多字节编码的UTF-8,因此一个片段的开头和结尾可能包含小数部分的字符,因此:对其进行解码比这要复杂得多。
因此,通常在缓冲区上检查List<string>
;如果是这样,您可以只使用简单的代码:
IsSingleSegment
不连续缓冲区的情况要困难得多;基本上,您在这里有两个选择:
- 将分段线性化为一个连续的缓冲区,可能从
if (buffer.IsSingleSegment) { string message = Encoding.UTF8.GetString(s.FirstSpan); DoSomethingWith(message); } else { // ... more complex }
租借了一个超大的缓冲区,并在租用缓冲区的正确部分上使用ArrayPool<byte>.Shared
- 在编码上使用
UTF8.GetString
API,并使用它填充新的字符串,这在较旧的框架上意味着覆盖新分配的字符串,或者在较新的框架中意味着使用GetDecoder()
API
坦率地说,“ 1”要简单得多。例如(未试用):
string.Create
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。