我有一个保持打开状态的
NamedPipeServerStream
,还有一个保持打开状态的 NamedPipeClientStream
。 NamedPipeServerStream
有一个保持打开状态的 UTF-8 StreamReader
。 NamedPipeClientStream
有一个 UTF-8 StreamWriter
,可以打开、写入一条消息、关闭然后重新打开以写入另一条消息。 StreamReader
和 StreamWriter
都是在 leaveOpen
标志设置为 true 的情况下打开的,因此 StreamWriter
在关闭时不会关闭 NamedPipeClientStream
。到目前为止,一切都很好。
我遇到一个问题,从第二次打开
StreamWriter
并发送消息时,StreamReader
会读取额外的 BOM。我已经设法在一个小示例程序中重新创建它。它是用.NET 6构建的。这是示例程序的代码:
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
读取后才包含。这里发生了什么?
System.Text.Encoding.UTF8
提供BOM它返回一个 UTF8Encoding 对象,该对象提供 Unicode 字节顺序标记 (BOM)。
StreamWriter.FlushAsync
将 BOM 附加到流中。
StreamWriter.Dispose
还附加 BOM。
所以如果你还想使用
Encoding.UTF8
,你需要将代码更改为:
using (var writer = new StreamWriter(namedPipeClient, Encoding.UTF8, 1024, true))
{
while (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}");
}
}
当然,你可以构造自定义的UTF8编码对象:
new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);