两个独立的C# .Net应用在同一台电脑上进行通信的最简单方法是什么?

5
我希望我的两个应用程序能够相互发送字符串,并根据字符串"做某事"执行不同的操作。
这是一个预概念模型,所以不需要安全措施,效率也可以尽可能低。
那么我该如何在尽可能少地付出努力的情况下实现这一目标呢?
(你可以尽自己所能解决这个问题)
8个回答

6

有几种机制可以实现这一点——可能最容易使用的是命名管道。我没有使用过,但我了解Windows通信基础(WCF)也很容易使用。

CodeProject上有许多关于WCF的文章 : http://www.codeproject.com/KB/WCF/?cat=3

使用WCF的好处是可以轻松地将您的进程移动到不同的系统中(如果对您的场景有意义的话)。


谢谢指点。如果这个项目能够在周二之后继续存在,我可能会开始阅读有关WCF的资料。 - Nifle

3

它们真的需要成为不同的应用程序吗?

你能否从第三个项目中启动两个不同线程的独立项目?

static void Main()
{
    new Thread(Project1.Program.Main).Start();
    new Thread(Project2.Program.Main).Start();
}

在这种情况下,您可以使用静态变量(在第四个项目中,由前两个项目引用),以建立它们之间的共享通信渠道。例如,您可以有两个生产者/消费者队列(向下滚动页面一半查看),一个用于每个方向。(您可能希望使队列只使用字符串,或制作一个通用队列,然后使用ProducerConsumer<string> 例如。如果您可以使用.NET 4.0 beta,则可以使用BlockingCollection<string>。)
这将是非常hacky的 - 即使没有不同的AppDomain的隔离,您也可能会看到从“应用程序”访问的静态变量的一些有趣影响,但这实际上是您要实现的目标。
您绝不能将此实现想法用于生产代码 - 但对于您所描述的情况,听起来“易于实现”是最重要的点。

如果项目层次结构不太清晰,这里有一个图形表示

        Launcher
       /        \
      /          \
   App 1       App 2
      \          /
       \        /
        \      /
      Shared stuff

为了让它变得更简单,你实际上可以只使用一个项目,并使其主方法使用同一项目中的方法启动两个不同的线程。到这个时候,它被视为两个应用程序的想法已经是虚假的了。另一方面,通过分离项目,可能更容易思考不同的应用程序。

不,他们现在不必这样做。既然你提到了这一点,这已经非常明显了。 - Nifle
我有点困惑。如果你说这种方法不应该在生产代码中使用,为什么你还建议我用它?我对此很感兴趣,因为我有一个合法的需求需要通过进程来分离事物。我正在构建一个应用程序,用户无法容忍整个应用程序崩溃,所以我需要通过进程来隔离不同的事物,以便如果某些事情发生了灾难性的错误,它不会破坏整个应用程序。我认为我将采用 WCF 路线。 - jasonh
@jasonh:因为两个应用程序在各种方面都应该被隔离开,而这种方法是绕过隔离的卑劣方式,只是为了让生活变得更容易。WCF 是一个更好的 正确 方法。 - Jon Skeet

2

最好、最有趣的方法是使用我所做的命名管道,我完全满意。

  class Client
{
    static void Main(string[] args)
    {
        using (var pipe = new NamedPipeClientStream("localhost", "FtechPipe", PipeDirection.InOut))
        {
            if (ServerCheck())
                pipe.Connect(5000);
            pipe.ReadMode = PipeTransmissionMode.Message;
            do
            {
                try
                {
                    Console.Write("Type Something> ");
                    var input = Console.ReadLine();
                    if (String.IsNullOrEmpty(input)) continue;
                    byte[] bytes = Encoding.Default.GetBytes(input);
                    pipe.Write(bytes, 0, bytes.Length);
                    var result = ReadMessage(pipe);
                    string me = Encoding.UTF8.GetString(result);
                    Console.WriteLine(me);
                    Console.WriteLine();
                }
                catch (IOException pipedEx)
                {
                    try
                    {
                        //inja bayad motmaeen beshi agent up hastesh 
                        //age ip nabood upesh kon 
                        //dobanre connect sho
                        pipe.Connect(5000);
                    }
                    catch (TimeoutException pipeTimeoutEx)
                    {

                    }

                }
            } while (true);
        }
    }

    private static bool ServerCheck()
    {
        var allProcesses = Process.GetProcesses();
        if (string.IsNullOrEmpty(allProcesses.Where(a => a.ProcessName == "Client.exe").FirstOrDefault()?.ToString()))
        {
            System.Diagnostics.Process.Start(@"C:\Client.exe");
            return true;
        }
        else
            return false;
    }
    private static byte[] ReadMessage(PipeStream pipe)
    {
        byte[] buffer = new byte[1024];
        using (var ms = new MemoryStream())
        {
            do
            {
                var readBytes = pipe.Read(buffer, 0, buffer.Length);
                ms.Write(buffer, 0, readBytes);
            }
            while (!pipe.IsMessageComplete);

            return ms.ToArray();
        }
    }
}


 class Server
{
    static void Main(string[] args)
    {

        using (var pipe = new NamedPipeServerStream(
            "FtechPipe", 
            PipeDirection.InOut, 
            NamedPipeServerStream.MaxAllowedServerInstances, 
            PipeTransmissionMode.Message))
        {
            Console.WriteLine("[*] Waiting for client connection...");
            pipe.WaitForConnection();
            Console.WriteLine("[*] Client connected.");
            while (true)
            {
                var messageBytes = ReadMessage(pipe);
                var line = Encoding.UTF8.GetString(messageBytes);
                Console.WriteLine("[*] Received: {0}", line);
                try
                {  
                    var response = Encoding.UTF8.GetBytes("Hello ");
                    pipe.Write(response, 0, response.Length);
                }
                catch (Exception ex)
                {
                    //Console.WriteLine(ex);
                    pipe.Disconnect();
                    Console.WriteLine("Disaconnected");
                    Console.WriteLine("[*] Waiting for client connection...");

                    //vaghti ke pipe Broke mishe yani ertebat ghat shode va bayad agent motmaeen beshe terminal up hast ya kheir
                    pipe.WaitForConnection();
                    Console.WriteLine("[*] Client connected.");
                }
            }
        }
    }

    private static byte[] ReadMessage(PipeStream pipe)
    {
        byte[] buffer = new byte[1024];
        using (var ms = new MemoryStream())
        {
            do
            {
                var readBytes = pipe.Read(buffer, 0, buffer.Length);
                ms.Write(buffer, 0, readBytes);
            }
            while (!pipe.IsMessageComplete);

            return ms.ToArray();
        }
    }
}

我很高兴在10年后这个问题仍然有意义。感谢您提供代码。 - Nifle

2

WCF是一种很好的方式,即使你开始深入研究它,它也可能变得复杂。

你可以定义一个简单的合同来接受字符串,然后在每个应用程序中实现该合同,在字符串到达时执行所需操作。在应用程序内部,您可以自托管服务,这意味着应用程序本身托管服务 - 因此您不需要IIS。将它们托管在已知端口上,在每个解决方案中添加Web服务引用,然后就可以开始了。


1

一种方法是使用.NET Remoting IpcChannel 类在同一台机器上的不同进程之间进行通信。


但是现在远程调用已经被弃用,WCF更受青睐。WCF也支持IPC。 - H H
确实,我自己也给WCF的答案点了赞。只是提到这个作为另一种选择。顺便说一下,我同意它并不是一种理想的技术(即使在WCF之前),但对于某些任务来说,它运行得相当不错。 - Mehrdad Afshari

1

我能想到最简单的方法是创建一个其他进程会检查的文件。

一种更“高级”和“明智”的方法是使用套接字和本地主机。

如果我真的想要实现它,我会尝试学习有关正确的IPC的知识。


这是一个糟糕的解决方案,因为它需要轮询。命名管道、WCF、本地套接字都可以使生产者和消费者阻塞——只在需要时运行。 - Foredecker
同时,每个人都知道如何创建文件,这使得它成为我所能想到的“最简单的方法”。 - weiqure

0

有很多非常简单的方法让应用程序以非常简单的方式进行通信。我认为其中一些最容易的方式如下:

  • 命名管道(Named Pipe)
  • 本地套接字(Local Sockets)
  • 共享内存(Shared Memory)

-2

我会选择使用套接字。


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