c# - 尝试从 NamedPipeClientStream 写入 NamedPipeServerStream 时如何修复“断管”错误
问题描述
我有一个程序,它必须与另一个从第一个调用的程序通信。我已经设法使用 NamedPipes 将所需的数据从第一个程序发送到第二个程序。当第二个程序关闭时,我需要将一些数据发送回第一个程序。我在第一个程序中设置了 NamedPipeServerStream,并从第二个程序的 Closing 事件中设置了 NamedPipeClientStream。现在,当我尝试从 ClientStream 写入时,我得到了一个损坏的管道错误。
这是第一个程序的代码:
private void CreateOverlay(object sender, EventArgs e)
{
if (oinstallfolder != null)
{
string processfilename = oinstallfolder.ToString() + "\\SecondProgram.exe";*/
string processfilename = "SecondProgram.exe";
if (File.Exists(processfilename))
{
foreach (Process clsProcess in Process.GetProcesses())
{
if (clsProcess.ProcessName.Equals("SecondProgram"))
{
this.threadHandleOverlayBounds = new Thread(new ThreadStart(this.ExchangeMapOverlayBoundsServer));
this.threadHandleOverlayBounds.Start();
this.threadHandleOverlayFile = new Thread(new ThreadStart(this.ExchangeMapOverlayFileServer));
this.threadHandleOverlayFile.Start();
ShowWindow(clsProcess.MainWindowHandle, SW_SHOWNORMAL);
SetForegroundWindow(clsProcess.MainWindowHandle);
return;
}
}
try
{
this.threadHandleOverlayBounds = new Thread(new ThreadStart(this.ExchangeMapOverlayBoundsServer));
this.threadHandleOverlayBounds.Start();
Logger.Logger.Write("Log.txt", "Starting Filethread serverside");
this.threadHandleOverlayFile = new Thread(new ThreadStart(this.ExchangeMapOverlayFileServer));
this.threadHandleOverlayFile.Start();
Process.Start(processfilename);
}
catch { }
}
}
}
private void ExchangeMapOverlayFileServer()
{
try
{
using (NamedPipeServerStream namedPipeServer = new NamedPipeServerStream("OverlayFilePipe", PipeDirection.In, 1, PipeTransmissionMode.Byte))
{
string line;
namedPipeServer.WaitForConnection();
StreamReader sr = new StreamReader(namedPipeServer);
line = sr.ReadLine();
namedPipeServer.Disconnect();
namedPipeServer.Close();
}
}
catch(Exception e)
{
Logger.Logger.Write("OverlayGenerator.txt", "namedPipeServer exception: " + e.Message + "\n" + e.StackTrace);
}
}
这是第二个程序的代码
this.Closing += (s, a) =>
{
Logger.Logger.Write("Log.txt", "Window Closing");
this.threadHandleOverlayFile = new Thread(new ThreadStart(this.HandleWindowClosing));
this.threadHandleOverlayFile.Start();
while (!done)
{
Thread.Sleep(100);
}
};
private void HandleWindowClosing()
{
if (!String.IsNullOrEmpty(this.latestSavedOverlayPath))
{
try
{
using (NamedPipeClientStream namedPipeClient = new NamedPipeClientStream(".", "OverlayFilePipe", PipeDirection.Out))
{
namedPipeClient.Connect();
StreamWriter sw = new StreamWriter(namedPipeClient);
sw.AutoFlush = true;
sw.WriteLine("testphrase");
namedPipeClient.Close();
this.done = true;
}
}
catch (Exception e) { Logger.Logger.Write("OverlayGenerator.txt", "Exception in Client: " + e.Message + "\n" + e.StackTrace); }
}
else
{
Logger.Logger.Write("OverlayGenerator.txt", "Latest saved OverlayPath = " + this.latestSavedOverlayPath);
}
}
我尝试了 Autoflush=true 和没有。有了它,我在生产线上遇到了一个破损的管道异常
sw.WriteLine("testphrase");
没有它,客户端只会运行到最后,什么也没有发生。
我的错误在哪里?谢谢你。
编辑
好吧,我就是不明白。我制作了一个测试程序,它的构建方式与实际程序相同。两个应用程序,第一个启动第二个。我在第一个应用程序的一个线程中启动管道服务器,在第二个应用程序中启动客户端,也在一个线程中。唯一的区别是,我在调试模式下运行这个测试项目,而我不能对实际程序执行此操作。现在,在测试程序中,这件事真的很简单,并且有效。当我在实际程序中使用完全相同的方法时,它不起作用。在测试程序中,我需要在 streamwriter 上使用 flush 并且我没有遇到异常。线程的同步由管道本身处理,如果我理解正确的话应该是这样。
大师长这样:
private const string CLIENTPROC = "C:\\Users\\Maik\\Source\\Repos\\PipeTest\\PipeClient\\obj\\x86\\Release\\PipeClient.exe";
private ManualResetEvent threadResetEvent;
private Thread threadHandlePipeSendLast;
private Process procClient;
private string msgPipeSend;
private volatile bool bMsgPipeSend;
public MainWindow()
{
InitializeComponent();
this.threadResetEvent = new ManualResetEvent(false);
System.Diagnostics.Debug.WriteLine("### starting thread");
this.threadHandlePipeSendLast = new Thread(new ThreadStart(this.ExchangeMapOverlayFileServer));
this.threadHandlePipeSendLast.Start();
}
private void ExchangeMapOverlayFileServer()
{
System.Diagnostics.Debug.WriteLine("server thread started");
Thread.CurrentThread.Name = "apocalypse";
try
{
using (NamedPipeServerStream namedPipeServer = new NamedPipeServerStream("ClosingPipe", PipeDirection.In, 1, PipeTransmissionMode.Byte))
{
string line;
namedPipeServer.WaitForConnection();
StreamReader sr = new StreamReader(namedPipeServer);
Thread.Sleep(100);
line = sr.ReadLine();
handleRecvMsgFromPipe(line);
namedPipeServer.Disconnect();
namedPipeServer.Close();
}
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine("### " + e.Message + "\n" + e.StackTrace);
}
}
private void handleRecvMsgFromPipe(string line)
{
this.outbox.Text = line;
}
private void buttonOpenFormClient_Click(object sender, EventArgs e)
{
#if DEBUG
#else
if (this.procClient == null)
{
try
{
this.procClient = Process.Start(new ProcessStartInfo(CLIENTPROC));
}
catch (Exception exc)
{
MessageBox.Show(exc.Message, "Error");
}
}
#endif
}
}
这就是客户端:
private ManualResetEvent threadResetEvent;
private Thread threadHandlePipeSendLast;
private string msgPipeSend;
private volatile bool bMsgPipeSend;
private bool done;
public MainWindow()
{
InitializeComponent();
this.threadResetEvent = new ManualResetEvent(false);
this.Closing += (s, a) =>
{
System.Diagnostics.Debug.WriteLine("+++ FormClosing started.");
this.threadHandlePipeSendLast = new Thread(new ThreadStart(this.HandleWindowClosing));
this.threadHandlePipeSendLast.Start();
while (!done)
{
Thread.Sleep(1000);
}
};
}
private void HandleWindowClosing()
{
try
{
using (NamedPipeClientStream namedPipeClient = new NamedPipeClientStream(".", "ClosingPipe", PipeDirection.Out))
{
namedPipeClient.Connect();
StreamWriter sw = new StreamWriter(namedPipeClient);
//sw.AutoFlush = true;
sw.WriteLine("last message");
namedPipeClient.WaitForPipeDrain();
namedPipeClient.Close();
this.done = true;
}
}
catch (Exception e) { System.Diagnostics.Debug.WriteLine(e.Message + "\n" + e.StackTrace); }
}
谁能告诉我,为什么这适用于测试应用程序而不是实际应用程序?我还尝试了从 Thread.Sleep(x) 在程序中的不同点通过 Thread.Join() 到像 WaitForPipeDrain 之类的管道方法(只是被忽略)的各种事情。
解决方案
推荐阅读
- apache-spark - Spark Structured Streaming 无法查看记录详细信息
- java - com.itextpdf.text.html.simpleparser.HTMLWorker ----- Java 中的 HTMLWorker.Parse 错误
- html - 在 html 或 css 中我的代码有问题
- c - 我可以使用 getchar() 来清除 scanf 和 fgets 之间的缓冲区吗?
- pygame - 为什么 play_button.rect.collidepoint(mouse_x , mouse_y) 不起作用?
- ios - SwiftUI 在特定选项卡索引/标签上加载 TabView 会导致第一个选项卡也加载
- python - 在烧瓶中使用电报上传上传文件?
- python - 将多个数据框保存在工作簿的单独选项卡/工作表中
- react-native - Resumable.js 在本机反应
- node.js - 当我在我的谷歌收件箱中收到一封电子邮件时如何调用我的 node.js API?