.NET 中的双工命名管道在读取期间写入时卡住(异步写入)
Duplex named pipe in .NET gets stuck when writing during a read (async write)
我有一个 .NET 应用程序,它通过 NamedPipe 从其父 NodeJS 应用程序读取消息,然后通过 stdout 写回消息。这工作正常,代码大致如下所示:
节点:
const { spawn } = require("child_process");
const net = require("net");
const os = require("os");
let proc;
function main() {
const socket = await setUpNamedPipe();
proc.stdout.setEncoding("utf-8");
proc.stdout.on("data", message => {
message.trimEnd().split(os.EOL).forEach(m => {
console.log(m);
})
});
socket.write("message1" + os.EOL);
socket.write("message2" + os.EOL);
socket.write("message3" + os.EOL);
socket.write("message4" + os.EOL);
socket.write("message5" + os.EOL);
}
function setUpNamedPipe() {
const pipeName = "MyPipe";
const pipePath = `\\.\pipe\${pipeName}`;
let myResolve;
const somePromise = new Promise(r =>
{
myResolve = r;
});
const server = net.createServer((socket) =>
{
myResolve(socket);
});
server.listen(pipePath, () =>
{
proc = spawn("Test.exe", [pipeName]);
});
return somePromise;
}
.NET 应用程序:
using System.IO.Pipes;
public class Program
{
public static void ListenForMessages(TextReader reader)
{
while (true)
{
string message = reader.ReadLine();
if (message == null)
{
return;
}
Console.WriteLine(message);
}
}
public static void Main(string[] args)
{
string pipeName = args[0];
using NamedPipeClientStream client = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut); // Just `In` doesn't work for some reason
client.Connect();
using TextReader reader = TextReader.Synchronized(new StreamReader(client));
Task.Factory.StartNew(() => ListenForMessages(reader), TaskCreationOptions.LongRunning).Wait();
}
}
如果我通过将 proc.stdout.on("data", ...)
替换为 socket.on("data", ...)
并将其设置为双工命名管道,并在我的 .NET 应用程序中创建一个 TextWriter
类似于我创建 TextReader
:
using TextReader reader = TextReader.Synchronized(new StreamReader(client));
然后使用 writer.WriteLine(...); writer.Flush();
而不是 Console.WriteLine
并在任务上进行写入,我没有从我的 .NET 应用程序中收到任何消息(除非我等待任务完成) .我错过了一步吗?
大致像:
public static void ListenForMessages(NamedPipeClientStream client)
{
using TextWriter writer = TextWriter.Synchronized(new StreamWriter(client));
using TextReader reader = TextReader.Synchronized(new StreamReader(client));
while (true)
{
client.WaitForPipeDrain();
string message = reader.ReadLine();
if (message == null)
{
return;
}
Task.Run(() => {
writer.WriteLine(message);
writer.Flush();
}); // only works if I add `.Wait()`
}
}
public static void Main(string[] args)
{
string pipeName = args[0];
using NamedPipeClientStream client = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut);
client.Connect();
Task.Factory.StartNew(() => ListenForMessages(client), TaskCreationOptions.LongRunning).Wait();
}
我只需要像这样将 PipeOptions.Asynchronous
标志传递给构造函数:
new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, PipeOptions.Asynchronous);
我有一个 .NET 应用程序,它通过 NamedPipe 从其父 NodeJS 应用程序读取消息,然后通过 stdout 写回消息。这工作正常,代码大致如下所示:
节点:
const { spawn } = require("child_process");
const net = require("net");
const os = require("os");
let proc;
function main() {
const socket = await setUpNamedPipe();
proc.stdout.setEncoding("utf-8");
proc.stdout.on("data", message => {
message.trimEnd().split(os.EOL).forEach(m => {
console.log(m);
})
});
socket.write("message1" + os.EOL);
socket.write("message2" + os.EOL);
socket.write("message3" + os.EOL);
socket.write("message4" + os.EOL);
socket.write("message5" + os.EOL);
}
function setUpNamedPipe() {
const pipeName = "MyPipe";
const pipePath = `\\.\pipe\${pipeName}`;
let myResolve;
const somePromise = new Promise(r =>
{
myResolve = r;
});
const server = net.createServer((socket) =>
{
myResolve(socket);
});
server.listen(pipePath, () =>
{
proc = spawn("Test.exe", [pipeName]);
});
return somePromise;
}
.NET 应用程序:
using System.IO.Pipes;
public class Program
{
public static void ListenForMessages(TextReader reader)
{
while (true)
{
string message = reader.ReadLine();
if (message == null)
{
return;
}
Console.WriteLine(message);
}
}
public static void Main(string[] args)
{
string pipeName = args[0];
using NamedPipeClientStream client = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut); // Just `In` doesn't work for some reason
client.Connect();
using TextReader reader = TextReader.Synchronized(new StreamReader(client));
Task.Factory.StartNew(() => ListenForMessages(reader), TaskCreationOptions.LongRunning).Wait();
}
}
如果我通过将 proc.stdout.on("data", ...)
替换为 socket.on("data", ...)
并将其设置为双工命名管道,并在我的 .NET 应用程序中创建一个 TextWriter
类似于我创建 TextReader
:
using TextReader reader = TextReader.Synchronized(new StreamReader(client));
然后使用 writer.WriteLine(...); writer.Flush();
而不是 Console.WriteLine
并在任务上进行写入,我没有从我的 .NET 应用程序中收到任何消息(除非我等待任务完成) .我错过了一步吗?
大致像:
public static void ListenForMessages(NamedPipeClientStream client)
{
using TextWriter writer = TextWriter.Synchronized(new StreamWriter(client));
using TextReader reader = TextReader.Synchronized(new StreamReader(client));
while (true)
{
client.WaitForPipeDrain();
string message = reader.ReadLine();
if (message == null)
{
return;
}
Task.Run(() => {
writer.WriteLine(message);
writer.Flush();
}); // only works if I add `.Wait()`
}
}
public static void Main(string[] args)
{
string pipeName = args[0];
using NamedPipeClientStream client = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut);
client.Connect();
Task.Factory.StartNew(() => ListenForMessages(client), TaskCreationOptions.LongRunning).Wait();
}
我只需要像这样将 PipeOptions.Asynchronous
标志传递给构造函数:
new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, PipeOptions.Asynchronous);