第十一章进程间通信
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
源代码: private void button1_Click(object sender, System.EventArgs e) { //在发送方,用FindWindow找到接受方的句柄,然后向接受方发送 WM_COPYDATA消息. //接受方在DefWndProc事件中,来处理这条消息. 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); } }
第11章 进程间通信
主要内容:
进程间通信的基本概念和原理; 几种典型的进程间通信的方法:剪切板、窗口消息、消 息队列、Sockets等。 编程模式和编程原理。
11.1 进程间通信
11.1.1 进程间通信的基本概念
程序是为了完成某项任务编排的语句序列,它 告诉计算机如何执行,因此程序是需要运行的。 进程能描述程序的执行过程而且可以作为共享 资源的基本单位。 两个不同进程可以通过互相发送消息进行合作, 消息是通过消息缓冲而在进程间相互传递的。 所谓进程通信是指进程之间可直接以较高的效 率传递较多数据的信息交换方式。这种方式中采用的 是通信机构,如消息发送和消息接收、邮箱结构等, 在进程通信时往往以信件形式(或称消息)传递信息。
图20.2 Windows的IPC 机制
11.2 窗口消息
窗口消息:一个应用用WM_COPYDATA消息向另一个应 用发送数据,接收数据的应用从COPYDATASTRUCT结构中 取数据 窗口消息的实现需要得到接收方窗口的句柄,使用 SendMessage向该进程发送消息。在发送方,用 FindWindow找到接收方句柄,然后向接收方发送 WM_COPYDATA消息 句柄:概念在WINDOWS编程中是一个很重要的概念, 在许多地方都扮演着重要的角色。
可选择的IPC机制:
否 网络 通信? 是 网络 DDE 命名管道 串行/并行通信 远程过程调用 分布式COM 命令行 剪贴板 窗口消息 DDE 匿名管道 动态连接库 共享内存和 文件映射 COM 消息队列 否 面向 连接? 是 Stream Sockets Datagram Sockets
源自文库邮件槽
Windows Sockets
接收方数据:重写窗体的DefWndProc()过程来接收自定义的消息: protected override void DefWndProc(ref System.Windows.Forms.Message m) { switch (m.Msg) { case WM_COPYDATA: string now = DateTime.Now.ToShortTimeString(); count++; COPYDATASTRUCT mystr = new COPYDATASTRUCT(); Type mytype = mystr.GetType(); mystr = (COPYDATASTRUCT)m.GetLParam(mytype); this.listBox1.Items.Add(now + ": " + mystr.lpData + " 收到的第" + count + "条信息"); break; default: base.DefWndProc(ref m); break; } }
20.2.2 WM_COPYDATA消息 一个应用发送WM_COPYDATA消息传递数据到另一个应用, 若发送该消息,以下列参数调用SendMessage函数 [DllImport("User32.dll",EntryPoint="SendMessage")] private static extern int SendMessage( int hWnd, // handle to destination window int Msg, // message int wParam, // first message parameter ref COPYDATASTRUCT lParam // second message parameter ); //使用extern 修饰符意味着方法在C# 代码的外部实现
寻找接收窗体 的句柄
找到句柄 是 将信息发送到 指定窗口
准备接收消息
否
弹出未找到句 柄的提示 结束
是否为 WM_COPYDA TA消息
否
是
接收消息并显示
结束
(a) 窗口消息发送端
(b) 窗口消息接收端
图20.3 窗口消息的编程框架
使用WM_COPYDATA消息有个前提,直到接收消息进 程的句柄,这是实现通信的关键。得到接收窗口句柄最直接的 方法,就是FindWindow()函数,找窗口类或者窗口名。 例如:在发送方,程序中通过 int WINDOW_HANDLER = FindWindow(null, @“接收 方窗体”);语句获得窗体句柄。 得到接收方窗体的句柄后,使用SendMessage()函数应 向该进程发送WM_COPYDATA消息。 SendMessage(WINDOW_HANDLER, WM_COPYDATA, 0, ref cds);
wParam:发送数据的窗口句柄。 lParam是指向含有发送数据的COPYDATASTRUCT结 构的指针。其返回值为布尔型,当接收消息的应用处理了该 数据,返回true,否则返回false 发送WM_COPYDATA消息时,SendMessage函数申请 到一个大小为cbData字节的内存块,并将数据从调用者的地 址空间复制到该内存块中,然后向目标窗口发送该消息。接 收消息的应用的窗口处理函数处理该消息时,lParam参数是 一个指向接收消息的应用的地址空间中的 COPYDATASTRUCT结构的指针,lpData成员是指向一个 复制内存块的指针,该地址反映了该内存块在接收消息的应 用的地址空间的位置。
在Windows环境中,句柄是用来标识项目的, WINDOWS程序中并不是用物理地址来标识一个内存块, 文件,任务或动态装入模块的,相反的,WINDOWS API给 这些项目分配确定的句柄,并将句柄返回给应用程序,然后 通过句柄来进行操作。 句柄是一个标识符,是拿来标识对象或者项目的,它就 象我们的姓名一样,每个人都会有一个,不同的人的姓名不 一样,但是,也可能有一个名字和你一样的人。从数据类型 上来看它只是一个16位的无符号整数。应用程序几乎总是通 过调用一个WINDOWS函数来获得一个句柄,之后其他的 WINDOWS函数就可以使用该句柄,以引用相应的对象。 在WINDOWS编程中会用到大量的句柄,比如: HINSTANCE(实例句柄),HBITMAP(位图句柄), HDC(设备 描述表句柄),HICON(图标句柄)等等。
安装Message Queuing Services
通过控制面板手工创建 控制面板-->添加/删除程序-->添加/删除Windows组 建-->消息队列服务安装MSMQ。接着要配置MSMQ,方法是打 开服务器资源管理器-->本机机器名-->消息队列-->专用队 列-->创建有名的队列(例如,队列名为aaa,是程序所需要 的)。 通过程序方式创建 if (MessageQueue.Exists(".\\Private$\\aaa")) MyMQ = new MessageQueue(".\\Private$\\aaa"); else MyMQ = MessageQueue.Create(".\\Private$\\aaa");
11.2.1 COPYDATASTRUCT结构
COPYDATASTRUCT结构包含通过WM_COPYDATA消息 传递到另一个应用的数据,其定义如下: typedef struct tagCOPYDATASTRUCT { DWORD dwData; DWORD cbData; PVOID lpData; } COPYDATASTRUCT, *PCOPYDATASTRUCT; dwData:指定传递到接收消息的应用的数据 cbData:指定成员lpData指向的数据的字节数 lpData:指向传递到接收消息的应用的数据的 指针。
进程Pi 消息发送 消 息 管 理
操作系统范围
进程Pj
发送机构
信道 接收机构
消息接收
发送机构 消 息 管 接收机构 理
消息发送
消息接收
图20.1 进程通信的一般模式
11.1.2 Windows下进程间的通信机制
IPC机制:Microsoft的API提供了应用程序之 间的通信和数据共享机制,称为进程间通信。 进行通信的应用程序可分为服务器和客户. 客户:向其他进程发出请求的应用或进程 服务器:响应客户请求的应用进程
其中: 添加如下定义: const int WM_COPYDATA = 0x004A; [DllImport("User32.dll", EntryPoint = "SendMessage")] private static extern int SendMessage( int hWnd, // handle to destination window int Msg, // message int wParam, // first message parameter ref COPYDATASTRUCT lParam // second message parameter ); //使用extern 修饰符意味着方法在C# 代码的外部实现 [DllImport("User32.dll", EntryPoint = "FindWindow")] private static extern int FindWindow(string lpClassName, string lpWindowName);
public struct COPYDATASTRUCT { public IntPtr dwData; public int cbData; [MarshalAs(UnmanagedType.LPStr)] public string lpData; //UnmanagedType,指定如何将参数或字段封送到非托管代码。 //LPStr,单字节、空终止的ANSI 字符串。可在System.String 或 System.Text.StringBuilder 数据类型上使用此成员。 } }
11.3 消息队列
利用MSMQ,可以 消息的程序框图
程 序 起 点 输入发 送文本 创建 队列 发送信息 到队列 结束 (a) 消息队列发送端 选择发 送图像
程 序 起 点 从队列提 取文本
从队列提 取图片
否 从队列提 取信息
队列为空
是 弹出 提示
结束
(b) 消息队列接收端 图20.5 消息队列的编程框架
11.2.3 实例程序 一个应用可以用WM_COPYDATA消息向另一个应用发送 数据,接收数据的应用从COPYDATASTRUCT结构中取数据, 可以将发送数据的应用视为服务器,接收数据的应用视为客 户,一个应用可以同时既为服务器又为客户。窗口消息的程 序框图 如下:
输入要传递的信息, 确认发送 程序起点 程序起点
所谓信件是指进程之间相互传递的赖以发生交 互作用的有结构的数据。 进程通信的一般模型,系统中的每个进程都可 以使用发送/接受系统调用向其他进程发送消息以及 接收来自别的进程的消息。 操作系统除了提供发送/接收俩个系统调用之 外,主要的任务是完成消息的管理与传递。 消息管理的功能包括:消息打包与分解,消息 队列管理,发送/接收机构管理。 信道指报文经历的通路,其具体的物理实现可 能是共享的主存区域或者外存盘块,也可能是总线 或电缆。