进程间通信

进程间通信
2011年01月01日
  1、共享内存
  使用CreateFileMapping函数创建文件映射,指定第一个参数为INVALID_HANDLE_VALUE表明在系统页文件中开辟共享内存,最后一个参数指定文件映射的名字。
  使用MapViewOfFile将已创建的文件映射映射到当前进程地址空间,可以读写访问。
  另一个进程可以使用OpenFileMapping通过制定文件映射名字,打开一个已经创建的文件映射。
  使用MapViewOfFile将已创建的文件映射映射到当前进程地址空间,可以读写访问。
  这样两个进程都可以讲共享内存映射到自己的进程地址空间,进行通信。
  通信完毕后需要使用UnmapViewOfFile取消映射,CloseHandle销毁文件映射。
  只适用于同一机器上的进程间通信。
  写数据的进程:
  
  #include
  
  #include
  
  #include
  
  using namespace std;
  
  
  
  
  int main()
  
  {
  
  //创建文件映射,指向操作系统页面文件
  
  HANDLE hFileMapping = ::CreateFileMapping((HANDLE)INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(int), "TestMem");
  
  
  //将共享内存映射到当前进程地址空间
  
  int* addr = (int*)::MapViewOfFile(hFileMapping, FILE_MAP_WRITE, 0, 0, sizeof(int));
  
  
  //向共享内存中写数据
  
  *addr = 23;
  
  getchar();
  
  
  //解除共享内存到当前进程地址空间的映射
  
  :: UnmapViewOfFile(addr);
  
  
  //销毁文件映射
  
  ::CloseHandle(hFileMapping);
  
  return 0;
  
  }
  
  
  #include
  
  #include
  
  #include
  
  using namespace std;
  
  
  
  
  int main()
  
  {
  
  //打开一个已命名的文件映射
  
  HANDLE hFileMapping = ::OpenFileMapping(FILE_MAP_READ, false, "TestMem");
  
  
  //将其映射到进程地址空间
  
  int* addr = (int*)::MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, sizeof(int));
  
  
  //读取共享内存中的数据
  
  cout
  getchar();
  
  
  
  //解除到进程地址空间的映射
  
  :: UnmapViewOfFile(addr);
  
  
  //关闭文件映射
  
  ::CloseHandle(hFileMapping);
  
  return 0;
  
  }
  
  2、命名管道
  服务器是唯一一个有权创建命名管道的进程,也只有它才能接受管道客户机的连接请求。
  对一个客户机应用来说,它只能同一个已命名的管道服务器建立连接。
  在客户机和服务器之间,一旦建好连接,两个进程都能对标准的Win32函数,在管道上进行数据的读取与写入。这些函数包括ReadFile和WriteFile等等。
  命名管道的命名格式: \\ServerName\Pipe\PipeName
  其中ServerName是服务器名字,Pipe固定表示管道,PipeName是管道名称。
  命名管道适用于单机或网络进程间通信。
  服务器端
  
  #include
  
  #include
  
  #include
  
  using namespace std;
  
  
  
  
  int main()
  
  {
  
  //创建一个命名管道
  
  HANDLE hPipe = ::CreateNamedPipe("\\\\.\\pipe\\MyPipe", PIPE_ACCESS_DUPLEX, 0, 2, 0, 0, 0, NULL);
  
  
  //将服务器端连接到命名管道,并监听是否有客户端连接到已创建的命名管道,若有则返回
  
  ::ConnectNamedPipe(hPipe, NULL);
  
  
  //从管道中读数据
  
  char cBuffer[1024] = {0};
  
  DWORD dwSize = 0;
  
  ::ReadFile(hPipe, cBuffer, 1024, &dwSize, NULL);
  
  cout
  
  //断开服务器端与命名管道的连接
  
  ::DisconnectNamedPipe(hPipe);
  
  
  //销毁管道
  
  ::CloseHandle(hPipe);
  
  return 0;
  
  }
  
  
  #include
  
  #include
  
  #include
  
  using namespace std;
  
  
  
  
  int main()
  
  {
  
  //客户端等待,直到指定的命名管道可用
  
  ::WaitNamedPipe(L"\\\\.\\pipe\\MyPipe", NMPWAIT_WAIT_FOREVER);
  
  
  //创建一个命名管道的实例
  
  HANDLE hPipe = ::CreateFile(L"\\\\.\\pipe\\MyPipe", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  
  
  //写数据
  
  const char* cWrite = "test pipe";
  
  DWORD dwSize = 0;
  
  ::WriteFile(hPipe, cWrite, (DWORD)strlen(cWrite)+1, &dwSize, NULL);
  
  
  //关闭管道
  
  ::CloseHandle(hPipe);
  
  return 0;
  
  }
  
  3、邮件槽
  邮件槽(Mailslots)提供进程间单向通信能力,服务器端创建邮件槽,客户端通过名字连接邮件槽,同一个邮件槽只允许客户端向服务器端发送数据。
  邮件槽命名与命名管道类似。
  支持单机或不同计算机之间的进程间通信。
  服务器端
  
  #include
  
  #include
  
  #include
  
  using namespace std;
  
  
  
  
  int main()
  
  {
  
  //创建一个邮件槽
  
  //第三个参数若为0,ReadFile即使读不到数据也立刻返回;若为MAILSLOT_WAIT_FOREVER,ReadFile将等待知道读到数据
  
  HANDLE hMail = ::CreateMailslot("\\\\.\\mailslot\\MyMail", 0, MAILSLOT_WAIT_FOREVER, NULL);
  
  
  //从邮件槽中读数据
  
  char cBuffer[1024] = {0};
  
  DWORD dwSize = 0;
  
  ::ReadFile(hMail, cBuffer, 1024, &dwSize, NULL);
  
  cout
  
  //销毁邮件槽
  
  ::CloseHandle(hMail);
  
  return 0;
  
  }
  
  
  #include
  
  #include
  
  #include
  
  using namespace std;
  
  
  
  
  int main()
  
  {
  
  //打开一个已命名的邮件槽
  
  //第二个参数必须设为GENERIC_WRITE,因为客户机只能向服务器写入数据。
  
  //第三个参数必须设为FILE_SHARE_READ,允许服务器在邮槽上打开和进行读操作。
  
  HANDLE hMail = ::CreateFile(L"\\\\.\\mailslot\\MyMail", GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  
  
  //写数据
  
  const char* cWrite = "test mail";
  
  DWORD dwSize = 0;
  
  ::WriteFile(hMail, cWrite, (DWORD)strlen(cWrite)+1, &dwSize, NULL);
  
  
  //关闭邮件槽
  
  ::CloseHandle(hMail);
  
  return 0;
  
  }
  
  4、socket连接
  服务器端和客户端通过socket连接通信,适用于网络间进程通信。
  服务器端
  
  #include
  
  #include
  
  #pragma comment (lib, "Ws2_32.lib")
  
  
  using namespace std;
  
  
  
  int main()
  
  {
  
  //初始化使用socket函数要用到的dll
  
  WSADATA wd;
  
  ::WSAStartup(MAKEWORD(2,2), &wd);
  
  
  //本机地址信息
  
  sockaddr_in addr;
  
  addr.sin_family = AF_INET;
  
  addr.sin_port = htons(1555);
  
  addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  
  
  //创建套接字,并与本机地址绑定
  
  SOCKET s = ::socket(AF_INET, SOCK_STREAM, 0);
  
  ::bind(s, (const sockaddr*)&addr, sizeof(addr));
  
  
  //监听该套接字,准备接收连接
  
  ::listen(s, 2);
  
  
  //等待客户端连接,若客户端连接则返回,否则一直等待
  
  //返回结果是用来通信的新套接字
  
  sockaddr_in client_addr;
  
  SOCKET ns = ::accept(s, (sockaddr*)&client_addr, NULL);
  
  
  //在新套接字上收数据
  
  while(1)
  
  {
  
  char cBuffer[1024] = {0};
  
  ::recv(ns, cBuffer, 1024, 0);
  
  cout
  }
  
  
  //关闭套接字
  
  ::closesocket(ns);
  
  ::closesocket(s);
  
  
  //ws2.dll的收尾工作
  
  ::WSACleanup();
  
  
  return 0;
  
  }
  
  
  #include
  
  #include
  
  #pragma comment (lib, "Ws2_32.lib")
  
  
  using namespace std;
  
  
  
  int main()
  
  {
  
  //初始化使用socket函数要用到的dll
  
  WSADATA wd;
  
  WSAStartup(MAKEWORD(2,2), &wd);
  
  
  //服务器地址信息
  
  sockaddr_in addr;
  
  addr.sin_family = AF_INET;
  
  addr.sin_port = htons(1555);
  
  addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  
  
  //创建套接字,并与服务器连接
  
  SOCKET s = ::socket(AF_INET, SOCK_STREAM, 0);
  
  ::connect(s, (const sockaddr*)&addr, sizeof(addr));
  
  
  //发送数据
  
  while(1)
  
  {
  
  char cData[1024] = {0};
  
  cin>>cData;
  
  ::send(s, cData, (int)strlen(cData)+1, 0);
  
  }
  
  
  //关闭套接字
  
  ::closesocket(s);
  
  
  //ws2.dll的收尾工作
  
  ::WSACleanup();
  
  
  return 0;
  
  }
  
  5、dll共享数据段
  动态链接库被加载后,映射到各自进程地址空间,但位于共享数据段内的变量为所有加载该dll的进程所共享。
  把需要共享的数据变量放入自定义的数据段中, 需要初始化的变量放入 #pragma data_seg()定义的数据段中;不需初始化的变量放入#pragma bss_seg()定义的数据段中。
  然后打开/SECTION 开关,请连接器为这些数据段定义共享属性。
  dll文件
  
  //共享数据段
  
  #pragma data_seg("Shared")
  
  __declspec(dllexport) char g_SharedBuffer[1024] = {0};
  
  #pragma data_seg()
  
  
  #pragma comment(linker, "/Section:Shared,rws")
  
  
  //非共享数据段
  
  __declspec(dllexport) char g_Buffer[1024] = {0};
  
  
  #include
  
  #pragma comment (lib, "..\\..\\dll\\release\\dll")
  
  
  using namespace std;
  
  
  
  int main()
  
  {
  
  //导入dll中的变量
  
  __declspec(dllimport) char g_Buffer[];
  
  __declspec(dllimport) char g_SharedBuffer[];
  
  
  //分别向两个变量中写入数据
  
  strcpy(g_Buffer, "not shared");
  
  strcpy(g_SharedBuffer, "shared");
  
  
  cout
  cout
  
  getchar();
  
  return 0;
  
  }
  
  
  #include
  
  #pragma comment (lib, "..\\..\\dll\\release\\dll")
  
  
  using namespace std;
  
  
  
  int main()
  
  {
  
  //导入dll中的变量
  
  __declspec(dllimport) char g_Buffer[];
  
  __declspec(dllimport) char g_SharedBuffer[];
  
  
  //输出结果
  
  cout
  cout
  
  getchar();
  
  return 0;
  
  }
  
  6、WM_COPYDATA消息
  发送方只需使用调用SendMessage函数,参数是目的窗口的句柄、传递数据的起始地址、WM_COPYDATA消息。
  接收方只需像处理其它消息那样处理WM_COPY DATA消息,这样收发双方就实现了数据共享。
  7、剪切板
  8、匿名管道
  在父进程和子进程之间,或同一父进程的两个子进程之间传输数据的无名字的单向管道。
  通常由父进程创建管道,然后由要通信的子进程继承通道的读端点句柄或写端点句柄,然后实现通信。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值