进程间通信的问题(C++高手进)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了进程间通信的问题(C++高手进)相关的知识,希望对你有一定的参考价值。

楼主接触C较少,所以这个实验不会做..
要求是:写俩程序P1,P2.P1运行创建子进程P2(即在P1中调用P2),其中P1为父进程,P2由P1创建,为P1子进程.
P1提供输入界面,读入用户输入.用户每输入一行字符,P1首先将字符放到和P2共享的内存缓冲区中,然后通过消息通知P2(消息自己定义)
P2提供显示界面,每接受到P1的一个消息,先从缓冲区读入数据,然后显示,并发P1消息,通知P1数据处理完毕.
P1在接受到P2的消息后,提示用户.以此类推.
所提供的主要函数:CreateProcess,CreateFileMapping,OpenFileMapping,FlushViewOfFile,UnmapViewOfFile,SendMessage,GetMessage.
求注释求程序,重赏

//////////////////////////////////////DDE回调函数; HDDEDATA CALLBACK DdeCallback(UINT wType,UINT wFmt,HCONV hConv,HSZ Topic,HSZ Item, HDDEDATA hData,DWORD lData1,DWORD lData2)  int I ;  char tmp[255];  switch(wType)     case XTYP_ADVSTART:   case XTYP_CONNECT://请求连接;    return ((HDDEDATA)TRUE);//允许;   case XTYP_ADVDATA: //有数据到来;    for(I=0;I<NITEM;I++)     if(Item==hszItem[I])           DdeGetData(hData,(PBYTE)tmp,255,0);//取得数据;      switch(I)             case 0:        SetDlgItemText(hWnd,IDC_STATIC2,tmp);        break;       case 1:        SetDlgItemText(hWnd,IDC_STATIC3,tmp);        break;               return ((HDDEDATA)DDE_FACK);//回执;   case XTYP_ADVREQ:   case XTYP_REQUEST://数据请求;    for(I=0;I<NITEM;I++)     if(Item==hszItem[I])      return(DdeCreateDataHandle(idlnst,(PBYTE)(LPCTSTR)ServerData[I],        ServerData[I].GetLength()+1,0,Item,wFmt,0));    return(0); ///////////////////////////////////////////////////// CddedemoDlg.cpp CDdedemoDlg::CDdedemoDlg(CWnd* pParent /*=NULL*/) : CDialog(CDdedemoDlg::IDD, pParent)  //AFX_DATA_INIT(CDdedemoDlg)   m_edit = _T("");  //AFX_DATA_INIT  // Note that LoadIcon does not require a subsequent DestroyIcon in Win32  m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); void CDdedemoDlg::DoDataExchange(CDataExchange* pDX)  CDialog::DoDataExchange(pDX);  //AFX_DATA_MAP(CDdedemoDlg)   DDX_Text(pDX, IDC_EDIT1, m_edit);  //AFX_DATA_MAP BEGIN_MESSAGE_MAP(CDdedemoDlg, CDialog) //AFX_MSG_MAP(CDdedemoDlg)  ON_WM_SYSCOMMAND()  ON_WM_PAINT()  ON_WM_QUERYDRAGICON()  ON_WM_TIMER()  ON_WM_DESTROY()  ON_EN_CHANGE(IDC_EDIT1, OnChangeEdit1) //AFX_MSG_MAP END_MESSAGE_MAP() //////////////////////////////////////////CDdedemoDlg message handlers BOOL CDdedemoDlg::OnInitDialog()  CDialog::OnInitDialog();  // Add "About..." menu item to system menu.  // IDM_ABOUTBOX must be in the system command range.  ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);  ASSERT(IDM_ABOUTBOX < 0xF000);  CMenu* pSysMenu = GetSystemMenu(FALSE);  if (pSysMenu != NULL)     CString strAboutMenu;   strAboutMenu.LoadString(IDS_ABOUTBOX);   if (!strAboutMenu.IsEmpty())       pSysMenu->AppendMenu(MF_SEPARATOR);    pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);       // Set the icon for this dialog. The framework does this automatically  // when the application's main window is not a dialog  SetIcon(m_hIcon, TRUE); // Set big icon  SetIcon(m_hIcon, FALSE); // Set small icon  // TODO: Add extra initialization here  hWnd=m_hWnd;  if (DdeInitialize(&idlnst,(PFNCALLBACK)DdeCallback,APPCMD_FILTERINITS| CBF_FAIL_EXECUTES|CBF_SKIP_CONNECT_CONFIRMS|CBF_FAIL_SELFCONNECTIONS| CBF_FAIL_POKES,0))     MessageBox("DDE SERVER初始化失败!");   return FALSE;    hlnst=AfxGetApp()->m_hInstance;  //创建DDE string  hszApp=DdeCreateStringHandle(idlnst,szApp,0);  hszTopic=DdeCreateStringHandle(idlnst,szTopic,0);  for(int I=0;I<NITEM;I++)   hszItem[I]=DdeCreateStringHandle(idlnst,pszItem[I],0);   //注册服务;   DdeNameService(idlnst,hszApp,0,DNS_REGISTER);   bConnect=FALSE;   SetTimer(1,1000,NULL);//开始定时;   return TRUE; // return TRUE unless you set the focus to a control void CDdedemoDlg::OnSysCommand(UINT nID, LPARAM lParam)  if ((nID & 0xFFF0) == IDM_ABOUTBOX)     CAboutDlg dlgAbout;   dlgAbout.DoModal();    else    CDialog::OnSysCommand(nID, lParam);   // If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework. void CDdedemoDlg::OnPaint()  if (IsIconic())     CPaintDC dc(this); // device context for painting   SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);   // Center icon in client rectangle   int cxIcon = GetSystemMetrics(SM_CXICON);   int cyIcon = GetSystemMetrics(SM_CYICON);   CRect rect;   GetClientRect(&rect);   int x = (rect.Width() - cxIcon + 1) / 2;   int y = (rect.Height() - cyIcon + 1) / 2;   // Draw the icon   dc.DrawIcon(x, y, m_hIcon);    else    CDialog::OnPaint();   // The system calls this to obtain the cursor to display while the user drags // the minimized window. HCURSOR CDdedemoDlg::OnQueryDragIcon()  return (HCURSOR) m_hIcon; void CDdedemoDlg::OnTimer(UINT nIDEvent)  // TODO: Add your message handler code here and/or call default  count++;  ServerData[1].Format("%d",count);  SetDlgItemText(IDC_STATIC1,ServerData[1]);  DdePostAdvise(idlnst,hszTopic,hszItem[1]);//通知更新;  if(!bConnect)//如果没有建立连接     hConv=DdeConnect(idlnst,hszApp,hszTopic,NULL);   //连接服务器端;   if(hConv) //如果建立成功       DWORD dwResult;    bConnect=TRUE;    for(int I=0;I<NITEM;I++)     DdeClientTransaction(NULL,0,hConv,hszItem[I],CF_TEXT,XTYP_ADVSTART, TIMEOUT_ASYNC,&dwResult);       CDialog::OnTimer(nIDEvent); void CDdedemoDlg::OnDestroy()  CDialog::OnDestroy();  // TODO: Add your message handler code here  KillTimer(1);//销毁定时;  DdeNameService(idlnst,0,0,DNS_UNREGISTER);//注销服务;  DdeFreeStringHandle(idlnst,hszApp);  DdeFreeStringHandle(idlnst,hszTopic);  for(int I=0;I<NITEM;I++)   DdeFreeStringHandle(idlnst,hszItem[I]);   DdeUninitialize(idlnst); void CDdedemoDlg::OnChangeEdit1()  // TODO: If this is a RICHEDIT control, the control will not  // send this notification unless you override the CDialog::OnInitDialog()  // function and call CRichEditCtrl().SetEventMask()  // with the ENM_CHANGE flag ORed into the mask.  // TODO: Add your control notification handler code here  UpdateData();  ServerData[0]=m_edit;  DdePostAdvise(idlnst,hszTopic,hszItem[0]); //通知DDE更新该数据项目; 参考技术A /*
windows,vs2010平台,进程间通信,图方便将两个进程都写在这一个源代码里面了
*/
#include <Windows.h>
int _tmain(int argc, _TCHAR* argv[])

//是否是子进程标志
bool isChildProcess = false;
//安全属性描述符,定义来让句柄可以在子进程中可以继承
SECURITY_ATTRIBUTES sa;
memset(&sa,0x0,sizeof(sa));
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;

//信号量,用于通知子进程已经有输入数据了,主进程中是创建,子进程中是打开
HANDLE hSemaphore = ::CreateSemaphore(&sa,0,100,_T("F8166D73-5BE5-4659-B024-87D9A7B18069"));
if ( NULL == hSemaphore )

perror("主进程中创建/子进程中打开信号量失败.");
return 0;

else if ( NULL != hSemaphore && ERROR_ALREADY_EXISTS == ::GetLastError() )

//这个是子进程
isChildProcess = true;


//创建文件映射(主进程中调用此函数是真实地创建,而子进程中调用此函数时相当于打开)
HANDLE hFileMap = ::CreateFileMapping(
INVALID_HANDLE_VALUE,//使用内存的分页中创建文件映射
&sa,//指定文件映射句柄可继承,如果不指定可继承,可以在子进程中用OpenFileMapping()函数打开已创建的文件映射
PAGE_READWRITE,//指定内存映射区访问保护标志
0,//内存大小高位
1024,//内存大小低位
_T("99A2E4DA-A6A5-41DD-9767-2824D45AD8BA")//映射名称
);

if ( NULL == hFileMap )

perror("主进程中创建/子进程中打开内存文件映射失败.");
::CloseHandle(hSemaphore);
return 0;

else if ( NULL != hFileMap && ERROR_ALREADY_EXISTS == ::GetLastError() )

//这个是子进程
isChildProcess = true;


//映射内存文件
LPVOID pMemFile = NULL;

//主进程/子进程中映射视图,因为子进程中hFileMap是打开同名的文件映射句柄而来的,所以虽然主进程和子进程都调用映射视图的函数MapViewOfFile(),
//但是在这两个进程中返回的pMemFile的地址是一样的
pMemFile =::MapViewOfFile(
hFileMap,
FILE_MAP_READ | FILE_MAP_WRITE,
0,
0,
1024
);
if ( NULL == pMemFile )

perror("主进程/子进程中创建映射视图失败.");
::CloseHandle(hSemaphore);
return 0;


//主进程中创建子进程
if ( ! isChildProcess )

TCHAR currentExeFileName[MAX_PATH];
::GetModuleFileName(NULL,currentExeFileName,MAX_PATH);
//主进程里创建子进程
PROCESS_INFORMATION pInfoChild;
memset(&pInfoChild,0x0,sizeof(pInfoChild));
STARTUPINFO stInfo;
memset(&stInfo,0x0,sizeof(stInfo));
stInfo.cb = sizeof(stInfo);
if ( ! ::CreateProcess(
currentExeFileName,//子进程名,就是再运行一个本程序的实例
NULL,//命令行
&sa,//子进程安全属性
&sa,//子进程的线程安全属性
TRUE,//是否可继承主进程句柄
NORMAL_PRIORITY_CLASS,//子进程创建标志
NULL,//使用默认环境变量
NULL,//使用默认起始位置
&stInfo,//子进程启动参数
&pInfoChild//子进程信息
) )

perror("主进程中创建子进程失败.");
::CloseHandle(hSemaphore);
return 0;

printf("创建子进程成功\n");

char inputStr[1024] = '0x0';
while ( strcmp(inputStr,"exit") != 0 )

fflush(stdin);
memset(inputStr,0x0,sizeof(inputStr));
Sleep(200);//防止显示出现错乱
printf("(主)输入一行字符(输入exit退出) = ");
scanf("%s",inputStr);
strcpy((char *)pMemFile,inputStr);
::ReleaseSemaphore(hSemaphore,1,NULL);


//等待子进程收到exit退出后再退出
::WaitForSingleObject(pInfoChild.hProcess,0);
::UnmapViewOfFile(pMemFile);
::CloseHandle(hFileMap);
::CloseHandle(hSemaphore);
return 0;

else

//子进程读取数据并显示
char inputStr[1024] = '0x0';
while ( strcmp(inputStr,"exit") != 0 )

::WaitForSingleObject(hSemaphore,INFINITE);
memset(inputStr,0x0,sizeof(inputStr));
strcpy(inputStr,(char *)pMemFile);
printf("\n(子)接收数据 = %s\n",inputStr);


//子进程收到exit退出后退出
::UnmapViewOfFile(pMemFile);
::CloseHandle(hFileMap);
::CloseHandle(hSemaphore);
return 0;


return 0;
参考技术B 这是典型的消费者和生产者的模式!
给出的几个函数无非是想让你用内存映射文件方法作为缓冲区(临界资源),然后通过给进程发送消息就OK了。
主要是在CreateFileMapping的时候要戴上名字,以方便另一个进程可以OpenFileMapping并使用。追问

其实是完全不懂操作啊- -表示楼主一直没深究过C++,连给给出的函数参数赋值还一知半解..伤不起啊

追答

查MSDN。再不懂的话就去论坛或者博客上看看!
不算太难!

本回答被提问者和网友采纳
参考技术C 提醒楼主,这个找操作系统的书看个上午,你就可以编代码。具体怎么写,哥忘了。其实注意函数原型就差不多了。 参考技术D MFC做的吗?
我也不会~~

以上是关于进程间通信的问题(C++高手进)的主要内容,如果未能解决你的问题,请参考以下文章

C++ 中是不是有用于远程进程间通信的 API?

c++下使用命名管道实现进程间通信

Linux-进程间通信

Linux-进程间通信

Linux-进程间通信

进程间通信:传递 C 风格的结构与 C++ 对象