提问人:Helena 提问时间:10/2/2023 更新时间:10/2/2023 访问量:41
在打开的 NamedPipeClientStream 上重新创建 UTF-8 StreamWriter 会导致服务器上出现额外的 BOM 字符
Recreating an UTF-8 StreamWriter on an open NamedPipeClientStream causes extra BOM characters on the server
问:
我有一个保持开放状态,一个保持开放状态。有一个保持打开状态的 UTF-8。有一个 UTF-8,用于打开、写入消息、关闭然后重新打开以写入另一条消息。和 the 都在标志设置为 true 的情况下打开,因此 在关闭时不会关闭。目前为止,一切都好。NamedPipeServerStream
NamedPipeClientStream
NamedPipeServerStream
StreamReader
NamedPipeClientStream
StreamWriter
StreamReader
StreamWriter
leaveOpen
StreamWriter
NamedPipeClientStream
我有一个问题,从第二次打开并发送消息开始,.我设法在一个小型示例程序中重新创建了它。它内置于 .NET 6 中。这是示例程序的代码:StreamWriter
StreamReader
using System.IO.Pipes;
namespace NamedPipeTest
{
internal class EncodingTest
{
private static NamedPipeServerStream namedPipeServer = new NamedPipeServerStream("mypipe", PipeDirection.InOut, NamedPipeServerStream.MaxAllowedServerInstances, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
private static NamedPipeClientStream namedPipeClient = new NamedPipeClientStream(".", "mypipe", PipeDirection.InOut, PipeOptions.Asynchronous);
static void Main(string[] args)
{
Console.WriteLine("Hello! You are the client. Press any key to send a request.");
Task[] tasks = new Task[]
{
Task.Run(() => Server()),
Task.Run(() => Client())
};
Task.WaitAll(tasks);
}
static async Task Server()
{
if (!namedPipeServer.IsConnected)
{
namedPipeServer.WaitForConnection();
}
using (var reader = new StreamReader(namedPipeServer, System.Text.Encoding.UTF8, false, 1024, true))
{
while (true)
{
string? line = await reader.ReadLineAsync();
Console.WriteLine($"Server: Received request: {line}");
if (!string.IsNullOrEmpty(line))
{
var lineBytes = System.Text.Encoding.UTF8.GetBytes(line);
var possibleBOMString = System.Text.Encoding.UTF8.GetString(new byte[] { lineBytes[0], lineBytes[1], lineBytes[2] });
if (possibleBOMString.Equals("\uFEFF"))
{
Console.WriteLine("Server: Whoa, what's up with the extra BOM?");
}
}
}
}
}
static async Task Client()
{
if (!namedPipeClient.IsConnected)
{
namedPipeClient.Connect(6000);
}
while (true)
{
using (var writer = new StreamWriter(namedPipeClient, System.Text.Encoding.UTF8, 1024, true))
{
Console.ReadKey(true);
Console.WriteLine("Client: Received key press, sending request.");
string? line = "Hello!";
await writer.WriteLineAsync(line);
await writer.FlushAsync();
Console.WriteLine($"Client: Sent request: {line}");
}
}
}
}
}
该程序的输出为:
Hello! You are the client. Press any key to send a request.
Client: Received key press, sending request.
Server: Received request: Hello!
Client: Sent request: Hello!
Client: Received key press, sending request.
Server: Received request: ?Hello!
Client: Sent request: Hello!
Server: Whoa, what's up with the extra BOM?
Client: Received key press, sending request.
Server: Received request: ?Hello!
Client: Sent request: Hello!
Server: Whoa, what's up with the extra BOM?
这种情况会无休止地继续下去。因此,该行在发送时不包含额外的 BOM,而是在 读取 之后。这是怎么回事?StreamReader
答:
2赞
shingo
10/2/2023
#1
System.Text.Encoding.UTF8
提供物料清单
它返回一个 UTF8Encoding 对象,该对象提供 Unicode 字节顺序标记 (BOM)。
StreamWriter.FlushAsync
将 BOM 附加到流中。StreamWriter.Dispose
将调用 ,因此它也会附加一个 BOM。Flush
解决方案是构造一个自定义的 UTF8Encoding 对象:
var enc = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
...
using (var writer = new StreamWriter(namedPipeClient, enc, 1024, true))
评论
0赞
Helena
10/2/2023
这是有道理的。然而,只是跳过冲洗并没有改变我的行为(为什么不呢,我想知道。为什么它不被冲洗仍然有效?另一件事...),我仍然得到BOM。不过,使用自定义 UTF8Enconding 对象解决了这个问题!我会从您的答案中删除带有注释的 Flush 调用的部分,然后我会将其标记为已接受的答案。
1赞
Stephen Cleary
10/2/2023
刷新仅写入尚未写入的 BOM,因此删除刷新不会执行任何操作。正确的解决方案是使用不带 BOM 的 UTF8。
0赞
shingo
10/2/2023
请注意“using”和“while”的顺序,两者都会附加一个 BOM,因此您需要同时修复两者。我假设您问题中的顺序是错别字,因为您在方法中将“使用”放在外面。Flush
Dispose
Server
0赞
Helena
10/2/2023
不,订单是故意的。如我问题的文本中所述,服务器始终使用相同的 StreamReader,而客户端为每个请求重新创建 StreamWriter。这是基于上下文的,应用程序当然比我给出的示例更复杂,因此顺序。
1赞
shingo
10/2/2023
如果这是有意为之,则必须使用自定义对象。我不认为默认编码有一天会改变,但由于您需要传递接下来的 2 个参数,因此您不能将 null 传递给编码参数。
评论