zoukankan      html  css  js  c++  java
  • 实现不同进程之间的通信

      进程之间的通信是为了解决不同进程之间的数据传输问题,这样可以让不同程序交互数据。实现进程通信的方式:1、剪切板;2、COM;3、内存映射文件;4、WCF

    1、剪切板Clipboard在进程间传送对象

      剪切板是一个供应用程序使用的公有区域。在.NET中定一个了一个DataFormats类,此类包含一些静态字段,定义了剪切板中可以存放的数据类型。使用Clipboard类可以向剪切板中放入数据。

      如将文字放入剪切板,使用方法SetDataObject即可:Clipboard.SetDataObject("剪切板文字2"); 在读取的时候,先判断剪切板中是否有文字,然后再读取:
    IDataObject data = Clipboard.GetDataObject();
    if (data.GetDataPresent(DataFormats.Text))
    {
        label1.Text = data.GetData(DataFormats.Text).ToString();
    }

      将自定义的数据放置到剪切板,自定义一个图片类,并标记为可序列化(此处使用的命名空间是:TestClipboard)。将自定义数据类型对象放置到剪切板的关键是DataObject类,它实现了IDataObject接口。它就像一个容器,存放将被放置在剪切板上的数据。

    [Serializable]
    public class MyPic
    {
        /// <summary>
        /// 图片
        /// </summary>
        public Image Img;
        /// <summary>
        /// 图片信息
        /// </summary>
        public string ImgInfo;
    }
    public void SetMyPicToClipboard()
    {
        MyPic obj = new MyPic();
        obj.Img = Properties.Resources.Image;
        obj.ImgInfo = "测试将自定义类型保存至剪切板";
        //创建数据对象,并将数据装入
        IDataObject dataObj = new DataObject(obj);
    
        //其他类型也可以放置在同一数据对象中
        /*
        dataObj.SetData(DataFormats.UnicodeText, "测试文字");
        dataObj.SetData(DataFormats.Bitmap, Properties.Resources.Image);
         */
        //复制到剪切板,第二个参数表示程序退出时不清空
        Clipboard.SetDataObject(dataObj, true);
    }

      但是,使用Clipboard.SetDataObject方法将一个DataObject对象放到剪切板后,外界访问时,需要指定对象的完整类型名称。如果某种数据类型只能在指定的进程中访问,则可以使用该方式,指定命名空间。

     //首先判断剪切板上是否有我的数据:需要完全限定命名空间类型
     if (Clipboard.ContainsData("WindowsFormsApplication1.MyPic"))
     {
         IDataObject dataObj = Clipboard.GetDataObject();//读取数据
         MyPic myPic = dataObj.GetData("WindowsFormsApplication1.MyPic") as MyPic;//转换数据
         pictureBox1.Image = myPic.Img;
         textBox1.Text = myPic.ImgInfo;
     }

    2、使用FileSystemWatcher实现进程同步

      该组件可以监控特定的文件夹或文件,比如在此文件夹中某文件被删除或内容被改变时引发对应的事件。通过该组件让多个进程同时监控一个文件,以此可以充当“临时”进程间通信渠道。
      实现进程同步的关键点是:正确设置文件的共享和读写权限。
    /// <summary>
    /// 实现写入数据
    /// </summary>
    /// <param name="fileName"></param>
    public void SetText(string fileName)
    {
        using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.Read))
        {
            using (StreamWriter writer = new StreamWriter(fs, Encoding.UTF8))
            {
                writer.Write("内容");
            }
        }
    }
    /// <summary>
    /// 实现读取数据
    /// </summary>
    /// <param name="fileName"></param>
    public void ReadText(string fileName)
    {
        using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
        {
            using (StreamReader reader = new StreamReader(fs, Encoding.UTF8))
            {
                string txt = reader.ReadToEnd();
            }
        }
    }

      然后,使用FileSystemWatcher组件的Changed事件监控文件是否发生改变。在网络应用程序中,可以使用此组件监控特定的专用于上传文件的文件夹,当发现用户上传文件之后,系统可以自动启动一系列的处理流程。

    3、使用内存映射文件(Memory Mapped File)实现进程通信

      含义:在内存中开辟一块存放数据的专用区域,这区域与硬盘上特定的文件相对应。进程将这块内存区域映射到自己的地址空间中,完成像访问普通内存一样访问它。windows中的系统分页文件和休眠文件就是如此实现的。需要引用命名空间System.IO.MemoryMappedFiles。

      MemoryMappedFile对象表示一个内存映射文件,通过它的CreateFromFile方法根据磁盘现有文件创建内存映射文件(注意,使用完后要立即释放资源,实际上它对应的是操作系统的核心对象)。其中,内存映射的容量在未指定时,默认与文件大小相等。在指定大小时,它的值不能小于文件的现有大小。若指定的大小大于磁盘文件大小,磁盘文件会自动增长到内存映射文件声明的容量大小。

      创建MemoryMappedFile对象后,不能直接对其进行读写,必须使用MemoryMappedViewAccessor对象(内存映射视图访问对象)操作 。可以用MemoryMappedFile对象的方法创建一个访问对象。其中,可以指定需要访问文件的范围,从第几个字节到第几个字节。在写入参数时,也需要指明想哪个位置写入什么。同时也可以使用MemoryMappedViewAccessor的Read方法读取数据。

    MemoryMappedFile memoryFile = MemoryMappedFile.CreateFromFile("Text.Config", FileMode.OpenOrCreate, "Config", 1400);//kb;
    MemoryMappedViewAccessor accessor = memoryFile.CreateViewAccessor(0, 1024);
    accessor.Write(0, '2');

      在同一个进程中,可以针对同一个内存映射文件创建多个“内存映射视图访问对象”,从而允许同时修改同一个文件的不同部分,在关闭这些对象时,由操作系统保证将所有修改都写回原始文件。

      MemoryMappedViewAccessor 的Write和Read有泛型方法,单类型只能是结构体类型(应用类型在程序运行时,计算机无法知道应该向内存映射文件写入多少字节数据,引用类型的对象位于托管堆中,其大小需要经过计算,但非常耗时(而且对象可能引用了其他对象),音效内存映射文件的效率)。
      可以使用序列化方式,将引用对象数据进行序列化后,写入内存映射文件中。
    MemoryMappedFile memoryFile = MemoryMappedFile.CreateFromFile("Text.Config", FileMode.OpenOrCreate, "Config", 1400);//kb;
    MemoryMappedViewStream stream = memoryFile.CreateViewStream();
    MyPic obj = new MyPic();
    stream.Seek(0, SeekOrigin.Begin);
    new BinaryFormatter().Serialize(stream, obj);

    4、使用WCF通过管道实现进程通信

      “管道(Pipe)”是Windows所提供的一种进程间通信机制,用于在两个进程间相互传送数据。Windows提供了两种类型管道:匿名管道(Anonymous Pipe)、命名管道(Named Pipe)

    1. 匿名管道:只允许单向通信,由于没有名字,因此要通信的两个进程应该是父子关系,父进程在创建子进程时,负责将代表匿名管道的句柄传送给子进程,子进程可以通过该句柄获取父进程传输的数据。其优点是占用资源少、效率高;缺点是通信进程必须为父子关系,限制了使用场景。
    2. 命名管道:这种类型的管道拥有一个在本机唯一的名字,可以用于在一个服务进程和多个客户进程之间进行单/双向通信。命名管道是基于消息的通信模式,即一个进程一次可以向另一方进程连续发生多个消息(消息之间通过消息的定界符进行划分),接收方通过定界符提取完整的消息。

      在命名空间System.IO.Pipes中,提供了一些用于实现基于管道的进程间通信,如AnonymousPipeClientStream和AnonymousPipeServerStream可用于实现匿名管道,而NamedPipeClientStream和NamedPipeServerStream可以实现命名管道。但相对于WCF,其比较繁琐,WCF的管道进程通信更加简便和灵活。

      WCF应用程序使用命名管道实现进程通信:WCF提供了一个NetNamedPipeBinding绑定,它可以在地层使用命名管道实现进程通信。

  • 相关阅读:
    hdu 4027 Can you answer these queries?
    hdu 4041 Eliminate Witches!
    hdu 4036 Rolling Hongshu
    pku 2828 Buy Tickets
    hdu 4016 Magic Bitwise And Operation
    pku2886 Who Gets the Most Candies?(线段树+反素数打表)
    hdu 4039 The Social Network
    hdu 4023 Game
    苹果官方指南:Cocoa框架(2)(非原创)
    cocos2d 中 CCNode and CCAction
  • 原文地址:https://www.cnblogs.com/pilgrim/p/11285218.html
Copyright © 2011-2022 走看看