zoukankan      html  css  js  c++  java
  • [Win]进程间通信——邮槽Mailslot

    进程间通信

    进程的地址空间是私有的。出于安全性的目的,如果一个进程不具有特殊的权限,是无法访问另外一个进程的内存空间的,也无法知道内存中保存的数据的意义。但是在一些具体的应用情况下需要多个进行相互配合,有时计算机用户也需要在多个应用程序之间交换数据。
    Windows系统下,在进程间通信或共享数据的方式如下。
    • 邮槽( Mailslot)。邮槽是最为简单的进程间数据共享方式,一个进程创建并拥有一个邮槽,其他进程都可以打开这个邮槽并向其发送消息。
    • 管道(Pipe)。实质是一种共享的内存,由一个进程创建,其他进程连接,并可进行双向的通信。
    • 剪贴板( Clipboard)。剪贴板是重要的进程间数据共享方式,所有的进程都可以设置和修改剪贴板,也都可以从剪贴板获取内容。
    • 消息,具体是指WM_COPYDATA消息。消息具有参数wParam和lParam。但是wParam和lParam最多是32位的。而WM_COPYDATA消息的参数不受wParam和lParam数据大小的限制,可以用于在进程间传递数据。
    • 网络。网络可以在不同主机上的不同程序间通信,当然也可以在相同主机上的不同程序间通信。
    • FileMapping. 

    邮槽

    使用邮槽通信的进程分为服务端和客户端。邮槽由服务端创建,在创建时需要指定邮槽名,创建后服务端得到邮槽的句柄。在邮槽创建后,客户端可以通过邮槽名打开邮槽,在获得句柄后可以向邮槽写入消息。
    邮槽通信是单向的,只有服务端才能从邮槽中读取消息,客户端只能写入消息。消息是先入先出的。客户端先写入的消息在服务端先被读取。
    通过邮槽通信的数据可以是任意格式的,但是一条消息不能大于424字节。
    邮槽除了在本机内进行进程间通信外,在主机间也可以通信。但是在主机间进行邮槽通信,数据通过网络传播时使用的是数据报协议(UDP),所以是一种不可靠的通信。通过网络进行邮槽通信时,客户端必须知道服务端的主机名或域名。

    实例

    server:
    /*进程间mailslot通信服务器端
    创建了一个名为“\\.\mailslot\sample_mailslot”的邮槽,然后使用GetMailslotInfo函数读取消息数量。如果没有消息,则等待3s获取信息。循环直至有消息到达,然后一次性读出全部消息。*/
    #include <windows.h>
    #include <stdio.h> 
    HANDLE hSlot;
    LPTSTR lpszSlotName = TEXT("\\.\mailslot\sample_mailslot");  
    void main()
    { 
    	DWORD cbMessage, cMessage, cbRead,cAllMessages; 
    	BOOL bResult;  
    	TCHAR lpszBuffer[1000]; 
    	TCHAR achID[80];  
    	cbMessage = cMessage = cbRead = 0; 
    	hSlot = CreateMailslot(
    		lpszSlotName,		// mailslot 名
    		0,							// 不限制消息大小 
    		MAILSLOT_WAIT_FOREVER,         // 无超时 
    		NULL); 
    
    	if (hSlot == INVALID_HANDLE_VALUE) 
    	{ 
    		printf("CreateMailslot failed with %d
    ", GetLastError());
    		return ; 
    	} 
    	else 
    		printf("Mailslot created successfully.
    "); 
    
    	while(1)
    	{
    		// 获取mailslot信息
    		bResult = GetMailslotInfo(hSlot, // mailslot 句柄 
    			(LPDWORD) NULL,               // 无最大消息限制
    			&cbMessage,                   // 下一条消息的大小
    			&cMessage,                    // 消息的数量
    			(LPDWORD) NULL);           // 无时限
    		if (!bResult) 
    		{ 
    			printf("GetMailslotInfo failed with %d.
    ", GetLastError()); 
    			return ; 
    		}  
    		printf("MAILSLOT_NO_MESSAGE 
    ");
    		if (cbMessage == MAILSLOT_NO_MESSAGE) 
    		{ 
    			// 没有消息,过一段时间再去读
    			Sleep(3000);
    			continue;
    		}  
    		printf("has MAILSLOT_NO_MESSAGE
    ");
    		cAllMessages = cMessage; 
    		while (cMessage != 0)  // 获取全部消息,有可能不只一条
    		{ 
    			// 提示信息
    			wsprintf(achID, "
    Message #%d of %d
    ", cAllMessages - cMessage + 1, cAllMessages); 			 
    			// 读取消息 
    			if(!ReadFile(hSlot,lpszBuffer,cbMessage,&cbRead,NULL))
    			{ 
    				printf("ReadFile failed with %d.
    ", GetLastError());  
    				return ; 
    			}  
    			lstrcat(lpszBuffer, achID); //连接
    			printf("Contents of the mailslot: %s
    ", lpszBuffer);//显示			
    			bResult = GetMailslotInfo(hSlot,NULL,&cbMessage,&cMessage,NULL); // 计算剩余的消息数,若cMessage=0,则退出子循环
    			if (!bResult) 
    			{ 
    				printf("GetMailslotInfo failed (%d)
    ", GetLastError());
    				return ; 
    			} 
    		} 
    	} 
    }
    client:
    /*进程间mailslot通信客户端
    客户端向邮槽发送消息需要首先打开邮槽,然后直接使用WriteFile函数写入。打开邮槽使用CreateFile函数。客户端在打开邮槽时需要知道邮槽名。*/
    #include <windows.h>
    #include <stdio.h> 
    LPTSTR lpszSlotName = TEXT("\\.\mailslot\sample_mailslot");		// mailslot名
    LPTSTR lpszMessage = TEXT("Test Message for mailslot "); // 通信的内容
    void main()
    {   
    	DWORD cbWritten; 
    	DWORD cbMessage;
    	// 打开mailslot
    	HANDLE hFile = CreateFile(lpszSlotName, 
    		GENERIC_WRITE,		// 可写
    		FILE_SHARE_READ,
    		(LPSECURITY_ATTRIBUTES) NULL, 
    		OPEN_EXISTING,		// 打开一个已经存在的mailslot,应该由服务端已经创建
    		FILE_ATTRIBUTE_NORMAL, 
    		(HANDLE) NULL); 
    	if (hFile == INVALID_HANDLE_VALUE) 
    	{ 
    		printf("CreateFile failed with %d.
    ", GetLastError()); 
    		return ; 
    	}
    	// 向mailslot写入
    	int num=50;
    	while(num)
    	{
    		Sleep(2000);
    		num--; 
    		if(!WriteFile(hFile, 
    			lpszMessage, 
    			(DWORD) (lstrlen(lpszMessage)+1),  
    			&cbWritten, 
    			(LPOVERLAPPED) NULL)) 
    		{ 
    			printf("WriteFile failed with %d.
    ", GetLastError()); 
    			return ; 
    		} 
    		printf("Slot written to successfully.
    "); 
    	}	
    	CloseHandle(hFile);  // 结束 
    }
    结果:
  • 相关阅读:
    【批处理】for命令
    【批处理】if命令,注释方式
    【批处理】choice命令,call 命令,start 命令,rem
    LoadLibrary加载动态库失败
    编译器如何实现静态变量只初始化一次
    汇编语言中 cs, ds,ss 的区别
    变量在内存中的位置
    call和ret指令
    函数调用
    浮动
  • 原文地址:https://www.cnblogs.com/dyllove98/p/3149464.html
Copyright © 2011-2022 走看看