因爲工作需要很多的遠程管理,一些現有的工具已經不能滿足實際要求。所以就 有了製作一個小型遠程控制檯的想法。
其實,它的工作原理很簡單。主要有兩部分組成,一個是對Cmd.exe 的標準輸入和輸出的重定向,另外有一個TCP連接來把本機的信息發送給遠程的主機。
以爲手上有兩個能實現上述功能的開源代碼,所以我的工作就是把它們揉在一起。但要求是Socket和ReStdInOut必須分離,Socket要不能使用MFC(爲了方便把邏輯移植到Linux或者和.Net連接),服務段程序必須是控制檯(爲了把它最終變成一個NT服務)。
Socket類是一個在網上找到的一輕量級WinSocket封裝,因爲覺得它寫的比我原來自己的封裝要好,而且最終要的是它已經儘可能使用的是標準C++庫(用的是Std::String,不是MFC::CString),給以後的移植方便了不少。
參考 C++ Socket Class for Windows
該類使用非常的方便
A simple Client
The following simple client connects to www.google.ch and get its front-website.
#include "Socket.h"
![]()
#include <iostream>
![]()
using namespace std;
![]()
![]()
int main() ...{
![]()
![]()
try ...{
SocketClient s("www.google.com", 80);
![]()
s.SendLine("GET / HTTP/1.0");
s.SendLine("Host: www.google.com");
s.SendLine("");
![]()
![]()
while (1) ...{
string l = s.ReceiveLine();
if (l.empty()) break;
cout << l;
cout.flush();
}
![]()
}
![]()
catch (const char* s) ...{
cerr << s << endl;
}
![]()
catch (String s) ...{
cerr << s << endl;
}
![]()
catch (...) ...{
cerr << "unhandled exception ";
}
![]()
return 0;
}
![]()
A simple echo Server
The following simple Server opens a port on 2000 and waits for incoming connections. Each connection is answered with the same line as was written (echoed).
![]()
/**//*
EchoServer.cpp
![]()
Copyright (C) 2002-2004 René Nyffenegger
![]()
This source code is provided 'as-is', without any express or implied
warranty. In no event will the author be held liable for any damages
arising from the use of this software.
![]()
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
![]()
1. The origin of this source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
![]()
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original source code.
![]()
3. This notice may not be removed or altered from any source distribution.
![]()
René Nyffenegger [email protected]
*/
![]()
![]()
#include "Socket.h"
#include <process.h>
#include <string>
![]()
![]()
unsigned __stdcall Answer(void* a) ...{
Socket* s = (Socket*) a;
![]()
![]()
while (1) ...{
std::string r = s->ReceiveLine();
if (r.empty()) break;
s->SendLine(r);
}
![]()
delete s;
![]()
return 0;
}
![]()
![]()
int main(int argc, char* argv[]) ...{
SocketServer in(2000,5);
![]()
![]()
while (1) ...{
Socket* s=in.Accept();
![]()
unsigned ret;
_beginthreadex(0,0,Answer,(void*) s,0,&ret);
}
return 0;
}
![]()
標準輸入輸入的重定向 用了一個CodeProjet 的項目
QuickWin - Turn a console application into a Windows program
項目裏的CRedirect類個人感覺非常好用,只需從他繼承一個自己的類,並且重寫4個虛函數
virtual void OnChildStarted(LPCSTR lpszCmdLine);
virtual void OnChildStdOutWrite(LPCSTR lpszOutput);
virtual void OnChildStdErrWrite(LPCSTR lpszOutput);
virtual void OnChildTerminate();
就輕鬆實現了標準輸入輸出的重定向。
其實核心技術都不是我自己寫的,但是得益於開源的力量,在瞭解了他們的源碼有我覺得完全可能把它們結合成一個新的應用。
我的方法是
1、Server初始化一個TCP Listener,等待客戶端接入。
2、客戶端接入服務段。
3、服務段連接客戶端後,開啓一個cmd.exe的進程,並重導向它的標準輸入、輸出和錯誤流。(這裏可以改進一下,使用API:CreateProcessWithLogonW或API:CreateProcessWithTokenW,是cmd.exe跑在制定的用戶下,因爲如果當前進程是NT服務的話,默認在System帳戶下,我問需要找到當前的登陸用戶,用它的進程跑Cmd.exe)
4、 用ReDir類的WriteStdIn和StdOut事件,反覆輸入和到處從Socket.ReandLine和Socket.SendLine的內容,以實現遠程控制檯的目的.
5、當客戶端用Exit結束cmd.exe時,服務段關閉連接自動退出。[你也改爲繼續等待下個連接]
界面:(因爲用的是Visual Studio 2005製作,運行需要MFC8的RunTime DLL)
先啓動服務程序:
![]()
接着使用 Telnet localhost 2000 連接服務,會得到一下狀態
![]()
你就可以向使用自己的本地控制檯一樣操作那臺機器了。
連續兩次exit指令 關閉連接、退出服務。
下載源碼
注意:我故意沒有隱藏打開的cmd.exe進程,可以開源碼裏OpenChildProcess了第二個參數爲0就可隱藏了。
整個製作時間:3小時。(開源真好:))
問題:沒有過濾掉輸出重複的命令