65.9K
CodeProject 正在变化。 阅读更多。
Home

使用双重SIMPLEX WCF 实现健壮的应用程序间通信

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.96/5 (12投票s)

2008 年 3 月 7 日

CPOL

4分钟阅读

viewsIcon

53330

downloadIcon

676

一种不可中断的方法, 用于同一台桌面上的两个应用程序交换数据

Pollux

引言

我需要找到一种方法,让运行在同一桌面上的两个应用程序相互通信。有很多方法可以做到这一点,但由于我以前没有使用过 WCF (Windows Communication Foundation),所以我想尝试一下。

背景

在 WCF 下,一个应用程序可以运行 WCF 主机,另一个应用程序可以运行 WCF 客户端。客户端连接到主机,然后可以向主机发送数据并从主机请求数据。如果使用回调,则主机端事件也可以将数据发送回客户端,而无需客户端请求它。

问题

WCF 看起来很理想,但我很快发现了一个问题。

由于我的两个应用程序都是普通桌面应用程序,可以由用户启动和停止,因此无法预测两个应用程序是否会同时运行。这是预期的,并且期望的行为是,如果另一个应用程序没有运行,则发送数据的应用程序会优雅地失败。

从客户端来说,没有问题。客户端只需连接到主机(如果尚未连接)并发送数据。如果主机不可用,客户端会优雅地失败。

从主机来说,存在一个问题。如果没有现有连接(例如,如果主机已停止并启动,从而断开连接),则主机上的事件将无法将数据发送到客户端。客户端必须首先发起连接,以便主机可以与其通信。

解决方案

我想到了两种解决方案:让客户端使用定时循环定期轮询主机以查看它是否正在运行,并建立通信;或者让主机通过发送一条消息(通过客户端正在监视的文件)来告诉客户端连接。两者都是可怕的黑客行为,并很快被否决。

我决定做的是运行**两个独立的** WCF 连接(双工)。每个应用程序将运行一个 WCF 主机来接收传入消息,并且每个应用程序将运行一个 WCF 客户端来发送传出消息。这是一个非常健壮的解决方案,并且不会因停止和启动应用程序而中断。如果需要,WCF 客户端只需重新建立连接。

下载内容

我提供了两个可下载的项目,因此您可以在 Visual Studio 的单独实例中运行它们中的每一个。只需运行并启动即可。一切都应该可以“开箱即用”。

您可能喜欢这种格式,也可能不喜欢。我想我可以将两者放在同一个解决方案中,但我讨厌 CodeProject 文章有一个需要同时运行的两个项目的单个解决方案。我总是最终从 Windows 资源管理器中将其中一个作为 EXE 运行,而将另一个在 Visual Studio 中运行,并且无法同时调试两者。

请注意,除了它们具有不同的名称并且管道的名称被反转之外,使得一个在另一个用于侦听的管道上进行通信,反之亦然,这两个项目是完全相同的。

另请注意,一个项目不引用另一个项目。我们依赖于在每个项目中都有 *Gemini.cs* 的相同副本。同样,您可能喜欢也可能不喜欢这样做,但是如果您愿意,您可以轻松地以另一种方式进行操作。

Using the Code

我已将工作代码封装在文件 *Gemini.cs* 中,并且两个项目都具有相同的副本。应该可以不变地使用它,只需将其放入您自己的项目中并像我一样调用它即可。

我不会深入研究 WCF 的工作原理。 这旨在作为您可以使用的实用工作代码片段,而不是教程。 WCF 在其他地方有非常详尽的记录,例如这里

这是示例窗体中的调用代码,展示了如何使用 *Gemini.cs*。

using Gemini;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace Castor
{
  public partial class Form1 : Form
  {
    private Gemini.Gemini gemini;

    public Form1()
    {
      InitializeComponent();
      gemini = new Gemini.Gemini("Castor", "Pollux", 
            WindowsFormsSynchronizationContext.Current);
      gemini.OnReceiveMessage += 
            new Gemini.Gemini.ReceiveMessageEventHandler(gemini_OnPassMessage);
    }

    private void button1_Click(object sender, EventArgs e)
    {
      if (gemini.SendMessage(this.textBox1.Text))
      {
        display(" [SENT] " + this.textBox1.Text);
      }
      else
      {
        display(" [FAIL] " + this.textBox1.Text);
      }
    }

    private void gemini_OnPassMessage(object sender, MessageEventArgs e)
    {
      display(" [RECV] " + e.Message);
    }

    private void display(string text)
    {
      if (this.listBox1.Items.Count > 14)
      {
        this.listBox1.Items.RemoveAt(0);
      }
      this.listBox1.Items.Add(DateTime.Now.ToLocalTime() + text);
    }
  }
}

奖励

如果包含第三个参数,即同步上下文,则传入消息的事件将在该线程上返回。如果您从主 UI 线程创建了Gemini实例(很可能就是这种情况),则可以避免更新 Windows 控件时的任何跨线程问题。无需InvokeRequired

注意事项

我不是 WCF 专家,实际上这是我的第一次尝试。该代码似乎没有任何问题。它似乎没有消耗内存或生成无限线程,但是如果您有任何意见,请告诉我。我会在需要时更新。

© . All rights reserved.