1、西安电子科技大学计算机学院实验报告题目: 进程通信 班级: 姓名: 学号: 西安电子科技大学操作系统原理实验报告管道一管道二内容摘要:通信进程个数 2个 采用的通信方式 匿名管道实验内容补充说明 无一、分析和设计1 理论分析匿名管道主要用在本地父子进程之间的通信,首先由父进程创建一个匿名管道,在创建成功后,便可以获得匿名管道的读写句柄,然后父进程就可以向匿名管道中写入和读取数据。要实现父子间通信,就要父进程中创建一个子进程,子进程可以继承和使用父进程的一些句柄。在创建子进程的过程中,必须将子进程的标准输入句柄设置为父进程的读管道的句柄,子进程的标准输出句柄设置为父进程的写管道的句柄,这样,父子
2、进程之间就可以通信了。2 总体设计先由父进程创建一个匿名管道,再由父进程获得读写句柄,构建读写的方式;由父进程创建子进程,实现父进程一样的通信功能。二、详细实现1、父进程的实现1)消息以及成员函数和成员变量的声明父进程 子进程西安电子科技大学操作系统原理实验报告public:afx_msg void OnBnClickedBtnCreatePipe(); /创建匿名管道afx_msg void OnBnClickedBtnWritePipe(); /写匿名管道afx_msg void OnBnClickedBtnReadPipe(); /读匿名管道void ParentReadPipe(voi
3、d); /定义父进程读匿名管道的成员函数void ParentWritePipe(void); /定义父进程写匿名管道的成员函数void CreateSecurityAttributes(PSECURITY_ATTRIBUTES pSa); /创建 SECURITY_ATTRIBUTES 结构的成员函数void CreateStartUpInfo(LPSTARTUPINFO lpStartUpInfo); /创建 STARTUPINFO 结构的成员函数void CreateNoNamedPipe(void); /创建匿名管道的成员函数/分别代表要从匿名管道中读的数据和要写到匿名管道中的数据CS
4、tring m_CStrReadPipe;CString m_CStrWritePipe;/保存创建匿名管道后所得到的对匿名管道的读写句柄HANDLE hPipeRead;HANDLE hPipeWrite;/保证匿名管道只创建一次西安电子科技大学操作系统原理实验报告BOOL m_PipeIsCreated;2)消息处理函数/创建匿名管道按钮的消息处理函数void CNoNamedPipeParentDlg:OnBnClickedBtnCreatePipe()if(m_PipeIsCreated = FALSE)this-CreateNoNamedPipe();/写入数据到匿名管道中按钮的消息
5、处理函数void CNoNamedPipeParentDlg:OnBnClickedBtnWritePipe()this-ParentWritePipe();/从匿名管道中读取数据按钮的消息处理函数void CNoNamedPipeParentDlg:OnBnClickedBtnReadPipe()this-ParentReadPipe();/接收数据void CNoNamedPipeParentDlg:ParentReadPipe(void);/发送数据void CNoNamedPipeParentDlg:ParentWritePipe(void)/创建 SECURITY_ATTRIBUTE
6、S 结构void CNoNamedPipeParentDlg:CreateSecurityAttributes(PSECURITY_ATTRIBUTES pSa)/这里必须将 bInheritHandle 设置为 TRUE,/从而使得子进程可以继承父进程创建的匿名管道的句柄pSa-bInheritHandle = TRUE;pSa-lpSecurityDescriptor = NULL;pSa-nLength = sizeof(SECURITY_ATTRIBUTES);/用来初始化新进程的 STARTUPINFO 成员void CNoNamedPipeParentDlg:CreateStart
7、UpInfo(LPSTARTUPINFO lpStartUpInfo)/创建匿名管道void CNoNamedPipeParentDlg:CreateNoNamedPipe(void);2、子进程的实现1)消息以及成员函数和成员变量的声明:protected:西安电子科技大学操作系统原理实验报告HICON m_hIcon;/ 生成的消息映射函数virtual BOOL OnInitDialog();afx_msg void OnPaint();afx_msg HCURSOR OnQueryDragIcon();DECLARE_MESSAGE_MAP()public:afx_msg void O
8、nBnClickedBtnWritePipe();afx_msg void OnBnClickedBtnReadPipe();/保存从父进程得到针对于匿名管道的读写句柄HANDLE hPipeRead;HANDLE hPipeWrite;/分别代表要从匿名管道中读的数据和要写到匿名管道中的数据CString m_CStrWritePipe;CString m_CStrReadPipe;/子进程读取匿名管道void ChildReadPipe(void);/子进程写匿名管道void ChildWritePipe(void);/子进程获取从父进程处继承得到的关于匿名管道的读写句柄void GetR
9、eadWriteHandleFromParent(void);/只需要获取一次匿名管道的读写句柄即可BOOL m_IsGettedParentHandle;2)消息处理函数/往匿名管道中写入数据按钮的消息处理函数void CNoNamedPipeChildDlg:OnBnClickedBtnWritePipe()/如果子进程还没有获得对匿名管道的读写句柄的话需要先获取句柄this-GetReadWriteHandleFromParent();ChildWritePipe();/从匿名管道中读取数据按钮的消息处理函数void CNoNamedPipeChildDlg:OnBnClickedBtn
10、ReadPipe()/如果子进程还没有获得对匿名管道的读写句柄的话需要先获取句柄this-GetReadWriteHandleFromParent();西安电子科技大学操作系统原理实验报告ChildReadPipe();/从匿名管道读取数据成员函数void CNoNamedPipeChildDlg:ChildReadPipe(void);/往匿名管道中写入数据void CNoNamedPipeChildDlg:ChildWritePipe(void)/需要获取继承自父进程的匿名管道读写句柄void CNoNamedPipeChildDlg:GetReadWriteHandleFromParen
11、t(void)if(this-m_IsGettedParentHandle = FALSE)hPipeRead = GetStdHandle(STD_INPUT_HANDLE);hPipeWrite = GetStdHandle(STD_OUTPUT_HANDLE);this-m_IsGettedParentHandle = TRUE;三、实验结果启动父进程可执行文件,并单击创建匿名管道按钮,此时会弹出子进程窗口(新建了进程):再在父进程的左边文本框中输入数据,单击写入数据按钮:再在子进程窗口中单击读取数据按钮西安电子科技大学操作系统原理实验报告四、心得体会通过本次试验,更深入的了解了进程间通
12、信中使用管道通信的方法,这种方法只能在父子进程之间通信,不能使用在其他地方,但在本地通信之间效率很高。六、附录1、父进程public:/创建匿名管道afx_msg void OnBnClickedBtnCreatePipe();/写匿名管道afx_msg void OnBnClickedBtnWritePipe();/读匿名管道afx_msg void OnBnClickedBtnReadPipe();/定义父进程读匿名管道的成员函数void ParentReadPipe(void);/定义父进程写匿名管道的成员函数void ParentWritePipe(void);/创建 SECURITY
13、_ATTRIBUTES 结构的成员函数void CreateSecurityAttributes(PSECURITY_ATTRIBUTES pSa);/创建 STARTUPINFO 结构的成员函数void CreateStartUpInfo(LPSTARTUPINFO lpStartUpInfo);/创建匿名管道的成员函数void CreateNoNamedPipe(void);/分别代表要从匿名管道中读的数据和要写到匿名管道中的数据CString m_CStrReadPipe;CString m_CStrWritePipe;西安电子科技大学操作系统原理实验报告/保存创建匿名管道后所得到的对匿
14、名管道的读写句柄HANDLE hPipeRead;HANDLE hPipeWrite;/保证匿名管道只创建一次BOOL m_PipeIsCreated;const int dataLength = 100;CNoNamedPipeParentDlg:CNoNamedPipeParentDlg(CWnd* pParent /*=NULL*/): CDialogEx(CNoNamedPipeParentDlg:IDD, pParent), m_CStrReadPipe(_T(“)m_hIcon = AfxGetApp()-LoadIcon(IDR_MAINFRAME);m_PipeIsCreate
15、d = FALSE;void CNoNamedPipeParentDlg:DoDataExchange(CDataExchange* pDX)CDialogEx:DoDataExchange(pDX);DDX_Text(pDX, IDC_EDIT_WRITE_PIPE, m_CStrWritePipe);DDX_Text(pDX, IDC_EDIT_READ_PIPE, m_CStrReadPipe);BEGIN_MESSAGE_MAP(CNoNamedPipeParentDlg, CDialogEx)ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKE
16、D(IDC_BTN_CREATE_PIPE, 西安电子科技大学操作系统原理实验报告/写入数据到匿名管道中按钮的消息处理函数void CNoNamedPipeParentDlg:OnBnClickedBtnWritePipe()this-ParentWritePipe();/从匿名管道中读取数据按钮的消息处理函数void CNoNamedPipeParentDlg:OnBnClickedBtnReadPipe()this-ParentReadPipe();/接收数据void CNoNamedPipeParentDlg:ParentReadPipe(void)DWORD dwRead;char *
17、 pReadBuf;CString cStrRecvData;pReadBuf = new chardataLength;memset(pReadBuf, 0, dataLength);if(!ReadFile(hPipeRead, pReadBuf, dataLength, return;cStrRecvData = “ 从匿名管道接收数据成功: “;cStrRecvData += pReadBuf;this-m_CStrReadPipe.Empty();this-m_CStrReadPipe = pReadBuf;UpdateData(FALSE);MessageBox(cStrRecvD
18、ata, TEXT(“提示“), MB_ICONINFORMATION);西安电子科技大学操作系统原理实验报告/发送数据void CNoNamedPipeParentDlg:ParentWritePipe(void)UpdateData();if(!this-m_CStrWritePipe.IsEmpty()char * pSendData;DWORD dwWrite;CString cStrSendData;/在这里需要将 Unicode 字符集转换为 ASCII 字符集pSendData = new charthis-m_CStrWritePipe.GetLength() + 1;mems
19、et(pSendData, 0, this-m_CStrWritePipe.GetLength() + 1);for(int i=0;im_CStrWritePipe.GetLength();i+)pSendDatai = (char)this-m_CStrWritePipe.GetAt(i);if(!WriteFile(hPipeWrite, pSendData, this-m_CStrWritePipe.GetLength() + 1, return;cStrSendData = “ 给匿名管道发送数据成功: “;cStrSendData += this-m_CStrWritePipe;t
20、his-m_CStrWritePipe.Empty();UpdateData(FALSE);MessageBox(cStrSendData, TEXT(“提示“), MB_ICONINFORMATION);elseMessageBox(TEXT(“ 请先输入要发送给匿名管道的数据 .“), TEXT(“提示“), MB_ICONERROR);西安电子科技大学操作系统原理实验报告/创建 SECURITY_ATTRIBUTES 结构void CNoNamedPipeParentDlg:CreateSecurityAttributes(PSECURITY_ATTRIBUTES pSa)/这里必须将
21、bInheritHandle 设置为 TRUE,/从而使得子进程可以继承父进程创建的匿名管道的句柄pSa-bInheritHandle = TRUE;pSa-lpSecurityDescriptor = NULL;pSa-nLength = sizeof(SECURITY_ATTRIBUTES);/用来初始化新进程的 STARTUPINFO 成员void CNoNamedPipeParentDlg:CreateStartUpInfo(LPSTARTUPINFO lpStartUpInfo)memset(lpStartUpInfo, 0, sizeof(STARTUPINFO);lpStartU
22、pInfo-cb = sizeof(STARTUPINFO);lpStartUpInfo-dwFlags = STARTF_USESTDHANDLES;/子进程的标准输入句柄为父进程管道的读数据句柄lpStartUpInfo-hStdInput = hPipeRead;/子进程的标准输出句柄为父进程管道的写数据句柄lpStartUpInfo-hStdOutput = hPipeWrite;/子进程的标准错误处理句柄和父进程的标准错误处理句柄一致lpStartUpInfo-hStdError = GetStdHandle(STD_ERROR_HANDLE);/创建匿名管道void CNoName
23、dPipeParentDlg:CreateNoNamedPipe(void)SECURITY_ATTRIBUTES sa;PROCESS_INFORMATION processInfo;STARTUPINFO startUpInfo;CreateSecurityAttributes(if(!CreatePipe(return;西安电子科技大学操作系统原理实验报告CreateStartUpInfo(if(!CreateProcess(TEXT(“NoNamedPipeChild.exe“), NULL, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NU
24、LL, CloseHandle(hPipeWrite);hPipeWrite = NULL;hPipeRead = NULL;MessageBox(TEXT(“ 创建子进程失败 .“), TEXT(“提示“), MB_ICONERROR);return;elsem_PipeIsCreated = TRUE;/对于 processInfo.hProcess 和 processInfo.hThread /这两个句柄不需要使用,所以释放资源CloseHandle(processInfo.hProcess);CloseHandle(processInfo.hThread);2、子程序/ 实现prote
25、cted:HICON m_hIcon;/ 生成的消息映射函数virtual BOOL OnInitDialog();afx_msg void OnPaint();afx_msg HCURSOR OnQueryDragIcon();DECLARE_MESSAGE_MAP()public:afx_msg void OnBnClickedBtnWritePipe();afx_msg void OnBnClickedBtnReadPipe();西安电子科技大学操作系统原理实验报告/保存从父进程得到针对于匿名管道的读写句柄HANDLE hPipeRead;HANDLE hPipeWrite;/分别代表要
26、从匿名管道中读的数据和要写到匿名管道中的数据CString m_CStrWritePipe;CString m_CStrReadPipe;/子进程读取匿名管道void ChildReadPipe(void);/子进程写匿名管道void ChildWritePipe(void);/子进程获取从父进程处继承得到的关于匿名管道的读写句柄void GetReadWriteHandleFromParent(void);/只需要获取一次匿名管道的读写句柄即可BOOL m_IsGettedParentHandle;const int dataLength = 100;CNoNamedPipeChildDlg
27、:CNoNamedPipeChildDlg(CWnd* pParent /*=NULL*/): CDialogEx(CNoNamedPipeChildDlg:IDD, pParent), m_CStrWritePipe(_T(“), m_CStrReadPipe(_T(“)m_hIcon = AfxGetApp()-LoadIcon(IDR_MAINFRAME);this-m_IsGettedParentHandle = FALSE;void CNoNamedPipeChildDlg:DoDataExchange(CDataExchange* pDX)CDialogEx:DoDataExcha
28、nge(pDX);DDX_Text(pDX, IDC_EDIT_WRITE_PIPE, m_CStrWritePipe);DDX_Text(pDX, IDC_EDIT_READ_PIPE, m_CStrReadPipe);BEGIN_MESSAGE_MAP(CNoNamedPipeChildDlg, CDialogEx)ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(ID_BTN_WRITE_PIPE, ChildWritePipe();/从匿名管道中读取数据按钮的消息处理函数void CNoNamedPipeChildDlg:OnBnClick
29、edBtnReadPipe()/如果子进程还没有获得对匿名管道的读写句柄的话需要先获取句柄this-GetReadWriteHandleFromParent();ChildReadPipe();/从匿名管道读取数据成员函数void CNoNamedPipeChildDlg:ChildReadPipe(void)DWORD dwRead;char * pReadBuf;CString cStrRecvData;pReadBuf = new chardataLength;memset(pReadBuf, 0, dataLength);/读取数据if(!ReadFile(hPipeRead, pRe
30、adBuf, dataLength, return;cStrRecvData = “ 从匿名管道接收数据成功: “;cStrRecvData += pReadBuf;this-m_CStrReadPipe.Empty();this-m_CStrReadPipe = pReadBuf;西安电子科技大学操作系统原理实验报告UpdateData(FALSE);MessageBox(cStrRecvData, TEXT(“提示“), MB_ICONINFORMATION);/往匿名管道中写入数据void CNoNamedPipeChildDlg:ChildWritePipe(void)UpdateDa
31、ta();if(!this-m_CStrWritePipe.IsEmpty()char * pSendData;DWORD dwWrite;CString cStrSendData;/在这里需要将 Unicode 字符集转换为 ASCII 字符集pSendData = new charthis-m_CStrWritePipe.GetLength() + 1;memset(pSendData, 0, this-m_CStrWritePipe.GetLength() + 1);for(int i=0;im_CStrWritePipe.GetLength();i+)pSendDatai = (cha
32、r)this-m_CStrWritePipe.GetAt(i);/写入数据if(!WriteFile(hPipeWrite, pSendData, this-m_CStrWritePipe.GetLength(), return;cStrSendData = “给匿名管道发送数据成功: “;cStrSendData += this-m_CStrWritePipe;this-m_CStrWritePipe.Empty();UpdateData(FALSE);MessageBox(cStrSendData, TEXT(“提示“), MB_ICONINFORMATION);elseMessageBo
33、x(TEXT(“ 请先输入要发送给匿名管道的数据 .“), 西安电子科技大学操作系统原理实验报告TEXT(“提示“), MB_ICONERROR);/需要获取继承自父进程的匿名管道读写句柄void CNoNamedPipeChildDlg:GetReadWriteHandleFromParent(void)if(this-m_IsGettedParentHandle = FALSE)hPipeRead = GetStdHandle(STD_INPUT_HANDLE);hPipeWrite = GetStdHandle(STD_OUTPUT_HANDLE);this-m_IsGettedParentHandle = TRUE;