当前位置: 首页 > news >正文

C# 进程同步,通信

 

进程之间通讯的几种方法:
常用的方法有:
1.使用内存映射文件
2.通过共享内存DLL共享内存
3.使用SendMessage向另一进程发送WM_COPYDATA消息.
 

发送WM_COPYDATA消息

比起前两种的复杂实现来,WM_COPYDATA消息无疑是一种经济实惠的一中方法.

WM_COPYDATA消息的主要目的是允许在进程间传递只读数据。Windows在通过WM_COPYDATA消息传递期间,不提供继承同步方式。SDK文档推荐用户使用SendMessage函数,接受方在数据拷贝完成前不返回,这样发送方就不可能删除和修改数据:
这个函数的原型及其要用到的结构如下:
SendMessage(hwnd,WM_COPYDATA,wParam,lParam);
其中,WM_COPYDATA对应的十六进制数为0x004A
wParam设置为包含数据的窗口的句柄。lParam指向一个COPYDATASTRUCT的结构:
typedef struct tagCOPYDATASTRUCT{
DWORD dwData;//用户定义数据
DWORD cbData;//数据大小
PVOID lpData;//指向数据的指针
}COPYDATASTRUCT;
该结构用来定义用户数据。
具体过程如下:

 

const int WM_COPYDATA = 0x004A;

private void button1_Click(object sender, System.EventArgs e)
{
int WINDOW_HANDLER = FindWindow(null,@"接收方窗体");
if(WINDOW_HANDLER == 0)
{
}
else
{
byte[] sarr = System.Text.Encoding.Default.GetBytes(this.textBox1.Text);
int len = sarr.Length;
COPYDATASTRUCT cds;
cds.dwData = (IntPtr) 100;
cds.lpData = this.textBox1.Text;
cds.cbData = len + 1;
SendMessage(WINDOW_HANDLER, WM_COPYDATA, 0, ref cds);

}
}
}
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPStr)] public string lpData;
}

}

 

// 接收方

this.Text = "接收方窗体";

protected override void DefWndProc(ref System.Windows.Forms.Message m)
{
switch(m.Msg)
{
case WM_COPYDATA:
COPYDATASTRUCT mystr = new COPYDATASTRUCT();
Type mytype = mystr.GetType();
mystr =(COPYDATASTRUCT)m.GetLParam(mytype);
this.textBox1.Text =mystr.lpData;
break;
default:
base.DefWndProc(ref m);
break;
}
}
}
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPStr)] public string lpData;

}

 

共享内存

发消息实现的C#进程间的通讯,和使用共享内存的应用范围是不同的,共享内存适用于共享大量数据的情况。
本文章利用了前面的一篇.net 1.1 下实现的信号量的类,在.net 1.1 下实现,如果在.net 2.0 下实现的话就用不到我的那个信号量的类了,因为这个类在.net 2.0是提供的。

首先还是定义非托管调用,如下:


const int INVALID_HANDLE_VALUE = -1;
const int PAGE_READWRITE = 0x04;
  //共享内存
  [DllImport("Kernel32.dll",EntryPoint="CreateFileMapping")]
  private static extern IntPtr CreateFileMapping(IntPtr hFile, //HANDLE hFile,
   UInt32 lpAttributes,//LPSECURITY_ATTRIBUTES lpAttributes,  //0
   UInt32 flProtect,//DWORD flProtect
   UInt32 dwMaximumSizeHigh,//DWORD dwMaximumSizeHigh,
   UInt32 dwMaximumSizeLow,//DWORD dwMaximumSizeLow,
   string lpName//LPCTSTR lpName
   ); 

  [DllImport("Kernel32.dll",EntryPoint="OpenFileMapping")]
  private static extern IntPtr OpenFileMapping(
   UInt32 dwDesiredAccess,//DWORD dwDesiredAccess,
   int bInheritHandle,//BOOL bInheritHandle,
   string lpName//LPCTSTR lpName
   ); 

  const int FILE_MAP_ALL_ACCESS = 0x0002;
  const int FILE_MAP_WRITE = 0x0002; 

  [DllImport("Kernel32.dll",EntryPoint="MapViewOfFile")]
  private static extern IntPtr MapViewOfFile(
   IntPtr hFileMappingObject,//HANDLE hFileMappingObject,
   UInt32 dwDesiredAccess,//DWORD dwDesiredAccess
   UInt32 dwFileOffsetHight,//DWORD dwFileOffsetHigh,
   UInt32 dwFileOffsetLow,//DWORD dwFileOffsetLow,
   UInt32 dwNumberOfBytesToMap//SIZE_T dwNumberOfBytesToMap
   ); 

  [DllImport("Kernel32.dll",EntryPoint="UnmapViewOfFile")]
  private static extern int UnmapViewOfFile(IntPtr lpBaseAddress); 

  [DllImport("Kernel32.dll",EntryPoint="CloseHandle")]
  private static extern int CloseHandle(IntPtr hObject);

然后分别在AB两个进程中定义如下两个信号量及相关变量;

  private Semaphore m_Write;  //可写的信号
  private Semaphore m_Read;  //可读的信号
  private IntPtr handle;     //文件句柄
  private IntPtr addr;       //共享内存地址
  uint mapLength;            //共享内存长
 
定义这两个信号量是为读写互斥用的。
在A进程中创建共享内存:
m_Write = new Semaphore(1,1,"WriteMap");
m_Read = new Semaphore(0,1,"ReadMap");
mapLength = 1024;
IntPtr hFile = new IntPtr(INVALID_HANDLE_VALUE);   
handle = CreateFileMapping(hFile,0,PAGE_READWRITE,0,mapLength,"shareMemory");
addr = MapViewOfFile(handle,FILE_MAP_ALL_ACCESS,0,0,0);

然后再向共享内存中写入数据:

m_Write.WaitOne();
byte[] sendStr = Encoding.Default.GetBytes(txtMsg.Text + '/0');
//如果要是超长的话,应另外处理,最好是分配足够的内存
if(sendStr.Length < mapLength)
      Copy(sendStr,addr);
m_Read.Release();


这是在一个单独的方法中实现的,可多次调用,但受信号量的控制。其中txtMsg是一个文本框控件,实际中可用任意字符串,加最后的'/0'是为了让在共享内存中的字符串有一个结束符,否则在内存中取出时是以'/0'为准的,就会出现取多的情况。
Copy方法的实现如下:

static unsafe void Copy(byte[] byteSrc,IntPtr dst)
  {
   fixed (byte* pSrc = byteSrc)
   {
    byte* pDst = (byte*)dst;
    byte* psrc = pSrc;
    for(int i=0;i<byteSrc.Length;i++)
    {
     *pDst = *psrc;
     pDst++;
     psrc ++;
    }
   }
  }
 
注意unsafe 关键字,在编译时一定要打开非安全代码开关。
最后不要忘了在A进程中关闭共享内存对象,以免内存泄露。
   UnmapViewOfFile(addr);
   CloseHandle(handle);

要在B进程中读取共享内存中的数据,首先要打开共享内存对象:
m_Write = Semaphore.OpenExisting("WriteMap");
m_Read = Semaphore.OpenExisting("ReadMap");
handle = OpenFileMapping(0x0002,0,"shareMemory");
读取共享内存中的数据:
   m_Read.WaitOne();
   string str = MapViewOfFile(handle,FILE_MAP_ALL_ACCESS,0,0,0);
   txtMsg.Text = str;
   m_Write.Release();
这里获取了字符串,如果要获取byte数组,请参考上面的Copy函数实现。
 
 
 
 
 
 

 

 

 

参考文章

c# 进程间同步实现 进程之间通讯的几种方法(转载)

相关文章:

  • 第三份CS地图--沙漠之战
  • 构建基于分布式SOA架构的统一身份认证体系
  • 傻瓜式Linux之三:安装软件
  • Python 3.5 socket OSError: [Errno 101] Network is unreachable
  • 华章1-2月份新书简介(2017年)
  • 专业网站打包/解包asp工具(E文精装版本)!
  • 【健康医疗】4步完成数据分析报表,让医疗数据转化为生产力
  • ORACLE查找并解除死锁进程
  • 云计算那些事
  • 推荐几本书给大家
  • javascript中this的用法
  • Foxmail邮件发不出去,都是Mcafee惹得祸
  • 百度编辑器 UEditor setContent()
  • 磨刀不误砍柴工
  • 关于statsd timer的几个指标
  • [译] 理解数组在 PHP 内部的实现(给PHP开发者的PHP源码-第四部分)
  • es6
  • export和import的用法总结
  • gitlab-ci配置详解(一)
  • JavaScript实现分页效果
  • JS基础篇--通过JS生成由字母与数字组合的随机字符串
  • JS基础之数据类型、对象、原型、原型链、继承
  • Mac 鼠须管 Rime 输入法 安装五笔输入法 教程
  • mysql常用命令汇总
  • Promise面试题,控制异步流程
  • Stream流与Lambda表达式(三) 静态工厂类Collectors
  • Three.js 再探 - 写一个跳一跳极简版游戏
  • windows下mongoDB的环境配置
  • 程序员该如何有效的找工作?
  • 紧急通知:《观止-微软》请在经管柜购买!
  • 如何设计一个比特币钱包服务
  • 首页查询功能的一次实现过程
  • 突破自己的技术思维
  • 我的面试准备过程--容器(更新中)
  • 小程序开发中的那些坑
  • 说说我为什么看好Spring Cloud Alibaba
  • 微龛半导体获数千万Pre-A轮融资,投资方为国中创投 ...
  • ​MPV,汽车产品里一个特殊品类的进化过程
  • # 达梦数据库知识点
  • # 再次尝试 连接失败_无线WiFi无法连接到网络怎么办【解决方法】
  • #android不同版本废弃api,新api。
  • (附源码)ssm教师工作量核算统计系统 毕业设计 162307
  • (附源码)计算机毕业设计大学生兼职系统
  • (简单) HDU 2612 Find a way,BFS。
  • (收藏)Git和Repo扫盲——如何取得Android源代码
  • (学习日记)2024.03.12:UCOSIII第十四节:时基列表
  • (一)基于IDEA的JAVA基础12
  • (原創) 如何解决make kernel时『clock skew detected』的warning? (OS) (Linux)
  • (转)shell中括号的特殊用法 linux if多条件判断
  • .class文件转换.java_从一个class文件深入理解Java字节码结构
  • .Net 6.0 处理跨域的方式
  • .NET Core WebAPI中使用swagger版本控制,添加注释
  • .NET Framework Client Profile - a Subset of the .NET Framework Redistribution
  • .NET/C# 推荐一个我设计的缓存类型(适合缓存反射等耗性能的操作,附用法)
  • .pyc文件还原.py文件_Python什么情况下会生成pyc文件?