两个C#进程之间最简单的进程间通信方法是什么?

91

我想在两个使用C#编写的进程之间建立通信,希望是异步和事件驱动的。

我不想为了处理极少发生的通信情况而在每个进程中运行线程。

哪种方案最佳?


2
我在我的博客上写了一篇关于使用WCF中的命名管道进行进程间通信的非常简单的示例文章。[https://dopeydev.com/wcf-interprocess-communication/] - Riain McAtamney
你是在谈论异步进程还是异步通信?第一种可以使用WCF或WebServices或任何基于TCP或管道的技术来完成。但异步通信需要像MSMQ、Azure Service Bus或RabbitMQ这样的队列技术。 - Dennis van der Stelt
相关:在C#中进行进程间通信的最简单方法是什么?(链接:https://dev59.com/-XI-5IYBdhLWcg3wio5k) - Sen Jacob
1
@RiainMcAtamney -- 链接已失效。 :( - Jesse Chisholm
9个回答

56

匿名管道.

使用BeginRead/BeginWrite和AsyncCallback进行异步操作。


23

如果您的进程在同一台计算机上,您可以简单地使用 stdio

这是我使用的一个网页截图工具:

var jobProcess = new Process();

jobProcess.StartInfo.FileName = Assembly.GetExecutingAssembly().Location;
jobProcess.StartInfo.Arguments = "job";

jobProcess.StartInfo.CreateNoWindow = false;
jobProcess.StartInfo.UseShellExecute = false;

jobProcess.StartInfo.RedirectStandardInput = true;
jobProcess.StartInfo.RedirectStandardOutput = true;
jobProcess.StartInfo.RedirectStandardError = true;

// Just Console.WriteLine it.
jobProcess.ErrorDataReceived += jp_ErrorDataReceived;

jobProcess.Start();

jobProcess.BeginErrorReadLine();

try
{
    jobProcess.StandardInput.WriteLine(url);
    var buf = new byte[int.Parse(jobProcess.StandardOutput.ReadLine())];
    jobProcess.StandardOutput.BaseStream.Read(buf, 0, buf.Length);
    return Deserz<Bitmap>(buf);
}
finally
{
    if (jobProcess.HasExited == false)
        jobProcess.Kill();
}

在主函数中检测参数

static void Main(string[] args)
{
    if (args.Length == 1 && args[0]=="job")
    {
        //because stdout has been used by send back, our logs should put to stderr
        Log.SetLogOutput(Console.Error); 

        try
        {
            var url = Console.ReadLine();
            var bmp = new WebPageShooterCr().Shoot(url);
            var buf = Serz(bmp);
            Console.WriteLine(buf.Length);
            System.Threading.Thread.Sleep(100);
            using (var o = Console.OpenStandardOutput())
                o.Write(buf, 0, buf.Length);
        }
        catch (Exception ex)
        {
            Log.E("Err:" + ex.Message);
        }
    }
    //...
}

6
如果目标进程需要一个图形用户界面,即如果 ProcessStartInfo.UseShellExecutetrue,那么这种方法将无法奏效。在这种情况下,您无法重定向标准输出和错误。 - Guido Domenici
@JayCroghan 我认为当它有GUI时是不能使用的。至少在客户端进程是从Web应用程序启动时是这样的。 - Mr Balanikas

9

102
那么,复杂的方法是什么呢? - dfasdljkhfaskldjhfasklhf
88
如果WCF是“最简单的方法”,我真的想哭:P - kizzx2
2
@kizzx2 我们正在大力学习WCF,一旦你度过了最初的困惑,WCF真的很酷。我发现这个人的简单实现非常有用 http://www.devx.com/codemag/Article/39837 - Charlie A
6
如果五页的 C# 和 XML 简单的话,我真的真的想哭了。 - Daniel Santos
WCF是REST的Web服务封装器。该问题涉及Windows进程。 - bytecode77



3

此外还有COM组件对象模型

虽然存在技术细节,但优势是您可以调用自己定义的方法。

MSDN提供C# COM互操作教程。请搜索,因为这些链接可能会更改。

若要立即开始,请转到此处...


3
如果可能的话,制作一个共享文件会更容易!
//out
File.AppendAllText("sharedFile.txt", "payload text here");
// in
File.ReadAllText("sharedFile.txt");

6
或者你可以把两块石头敲在一起... 这种方法需要轮询并在锁定文件时进行额外的错误处理等,而且它不是事件驱动的。当然,它可能有效,但是... - LordWabbit
我认为这不是一个糟糕的答案。.NET提供了一个非常整洁的类来实现事件驱动:https://dev59.com/6XRB5IYBdhLWcg3wF0DH#721743 - Kasper Cottaar
@LordWabbit 它可以工作,而且确实如此。问题不在于“最佳”方法,而在于“最简单”的方法。这是最简单的方法之一。这个答案可能不是最好的,但肯定比你的敲石头类比或者说整个傲慢的评论更有用。 - Daniel

2

2
在安全性不是一个问题且您的约束条件是两个C#进程在同一台计算机上时,用于进程间通信的最简单的解决方案是Remoting API。现在Remoting是一项传统技术(并非已弃用),不鼓励在新项目中使用,但其工作效果良好,并且无需很多繁文缛节即可启动。
有一篇在MSDN上的优秀文章介绍了如何使用Remoting框架中的类进行设置简单的远程服务端和客户端(感谢Greg Beech的发现)。
我建议先尝试这种方法,然后再尝试将代码移植到 WCF(Windows Communication Framework)。WCF 有几个优点(更好的安全性、跨平台),但它也必然更加复杂。幸运的是,MSDN 有一篇非常好的文章介绍从 Remoting 到 WCF 的代码移植(链接)
如果你想马上开始使用 WCF,这里有一个很棒的教程(链接)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接