本文提出采用Win98
撥號網絡服務器、FTP
協議和免費個人主頁空間站點實現控制遠程計算機撥號上網并獲取其IP
地址的方法,該方法在實施遠程維護等方面具有較高的實用價值。
一、問題的提出
許多計算機系統需要7 ×24
小時穩定可靠運行,當出現突發事件時,要求能對系統實施遠程系統維護以便排除故障,此時就需要本地計算機和遠程系統建立通信連接,通過相應的工具軟件實施遠程維護。在建立遠程通信連接時,通常采用Modem
撥號方法將遠端Modem 置為自動應答方式,由本地Modem
通過公用電話網發起呼叫來建立通信連接。當主、被叫Modem
所在地之間的長途費率較高時,經常的遠程維護將帶來較高的長途話費開支。本文提出通過Internet
建立兩臺計算機之間通信的方法。
二、通知遠程計算機撥號上網
遠程計算機安裝Win98
操作系統,在安裝了撥號網絡服務器組件后,便可配置為一臺撥號網絡服務器,供本地計算機通過電話網撥號建立通信連接,并訪問遠程計算機上的共享資源。在撥號通信鏈路上可綁定TCP/IP
等通信協議,Win98 撥號服務器給每個撥入計算機分配一個獨立的IP
地址,同時也給自身分配一個IP 地址,這些IP
地址具有相同的網絡編號,同屬于一個通信子網,服務器的主機編號為1,撥入計算機的主機編號依次從2
開始編起。另外,Win98
撥號服務器還提供了密碼保護功能,撥入計算機只有在提供正確的密碼情況下,才能成功建立起撥號連接。
當本地計算機要通知遠程計算機撥號登錄Internet
時,首先通過電話撥號和遠程計算機建立撥號連接,獲取遠程計算機分配給本機的IP
地址,并經處理得到遠程計算機的IP 地址,然后,和遠程計算機建立TCP/IP
連接,并送出命令通知遠程計算機準備斷開撥號連接,登錄Internet,當本地計算機收到遠程計算機確認信息后,便可中斷和遠程計算機的撥號連接,也準備登錄Internet。
三、獲取遠程計算機Internet IP 地址
在取得遠程計算機Internet IP 地址前,本地計算機是無法通過Internet
和遠程計算機進行實時通信的。遠程計算機登錄Internet,獲取動態IP
地址后,可通過發電子郵件方式將動態IP
地址通知本地計算機,也可通過將動態IP
地址保存在遠程、本地計算機都可訪問到的FTP
服務器文件中,供本地計算機讀取。本文采用后一種方法,若沒有合適的FTP
服務器,可到提供免費主頁空間允許以FTP 方式維護的Web
站點上申請一塊空間,供遠程、本地計算機共同訪問。
本地計算機登錄Internet 后,用FTP 協議讀取指定FTP
服務器上含有遠程計算機動態IP
地址的文本文件,從而取得遠程計算機的Internet IP
地址,然后,本地計算機便可通過Internet 和遠程計算機啟動任何基于TCP/IP
連接的通信應用程序,如利用Pcanywhere
控制遠程計算機,并可通過遠程計算機訪問與遠程計算機相連的整個網絡資源,達到對遠程計算機系統進行維護的目的。
四、通知遠程計算機斷開Internet 連接
當本地計算機和遠程計算機通信結束后,便可通知遠程計算機斷開Internet
連接。利用遠程計算機的Internet IP
地址,本地計算機和遠程計算機建立TCP/IP 連接,送出斷開Internet
指令,遠程計算機收到指令后,回送確認消息,斷開Internet
連接,等待下一個命令的到來。
五、程序實現
本地、遠程計算機運行的是同一道程序,通過不同的命令按鈕來激活本地、遠程計算機程序所具有的不同功能。程序采用VC
++6.0 編寫,在Win98
環境下調試運行通過。限于篇幅,下面只給出程序的主要部分及注釋說明,并省去了一些出錯處理環節。
// 宏定義
#define MAX_PENDING_CONNECTS 2
#define NO_FLAGS_SET 0
#define MY_MSG_LENGTH 100
// 全局變量
HRASCONN hCon; //RAS 連接句柄
HWND hWin;
HINSTANCE hInst;
DWORD ThreadId=0;
HANDLE hThread=NULL;
char cRemoteIP[50]; //remote IP 地址
SOCKET serv_sock,rsock; // 服務端
// 建立撥號連接函數,
成功返回TRUE else FALSE
// szEntry 撥號連接名szPhone
電話號碼szUser 和szPassword
分別為internet 的用戶名和口令
BOOL StartCon( HWND hWnd,char *szEntry,char
*szUser,char *szPassword,char *szPhone )
{
RASDIALPARAMS rdParams;
DWORD dwRet;
char szBuf[300];
rdParams.dwSize = sizeof(RASDIALPARAMS);
lstrcpy(rdParams.szEntryName,szEntry);
strcpy(rdParams.szPhoneNumber,szPhone);
rdParams.szCallbackNumber[0] = '\0';
strcpy(rdParams.szUserName,szUser);
strcpy(rdParams.szPassword,szPassword);
rdParams.szDomain[0] = '\0';
// 以下開始同步撥叫網絡
dwRet = RasDial( NULL, NULL,
&rdParams, 0L, NULL, &hCon );
return TRUE;
}
// 通過FTP 協議讀寫FTP 服務器上
文件的函數cFlag =0 寫=1 讀,讀寫
成功時返回所讀寫的字節數
DWORD FtpWriteRead(char *cFtpHost,char *
cFile,DWORD dwLen,char *buf,char cFlag)
{
HINTERNET hInternet,hHost,hFile;
DWORD dwLength,dwError;
hInternet=InternetOpen("FZYXB",LOCAL
_INTERNET_ACCESS,
NULL,0,0);
hHost=InternetConnect(hInternet,cFtpHost,
INTERNET_INVALID_PORT_NUMBER,
"fzxucm","abc505",
INTERNET_SERVICE_FTP,INTERNET
_FLAG_PASSIVE,0);
if ( cFlag == 0 ) // 寫
hFile=FtpOpenFile(hHost,cFile,GENERIC_WRITE,
FTP_TRANSFER_TYPE_BINARY,0);
else
hFile=FtpOpenFile(hHost,cFile,GENERIC_READ,
FTP_TRANSFER_TYPE_BINARY,0);
if( !hFile)
{
if ( (dwError=GetLastError()) == 12003 )
ShowMsg(hWin,"文件不存在");
InternetCloseHandle(hHost);
InternetCloseHandle(hInternet);return 0L;
}
if ( cFlag == 0 )
InternetWriteFile(hFile,buf,dwLen, &dwLength);
else
InternetReadFile(hFile,buf,dwLen, &dwLength);
InternetCloseHandle(hFile);InternetCloseHandle(hHost);
InternetCloseHandle(hInternet);
return dwLength;
}
// 通過FTP 協議刪除FTP 服務器上
文件的函數cFtpHost 主機地址cFile 文件名
BOOL MyFtpDeleteFile(char *cFtpHost,char *cFile)
{
HINTERNET hInternet,hHost;
hInternet=InternetOpen("FZYXB",
LOCAL_INTERNET_ACCESS,
NULL,0,0);
hHost=InternetConnect(hInternet,cFtpHost,
INTERNET_INVALID_PORT_NUMBER,"fzabc",
"b505",INTERNET_SERVICE_FTP,INTERNET
_FLAG_PASSIVE,0);
FtpDeleteFile(hHost,cFile);
InternetCloseHandle(hHost);InternetCloseHandle(hInternet);
return TRUE;
}
// 本地計算機運行線程函數pp 功能代碼
void CallThread(void *pp )
{
DWORD *dwId,dwLen, ret,ll;
RASPPPIP rip;
char szIp[50], *pdest;
dwId=(DWORD *)pp;
switch( *dwId )
{
case IDC_CALL:
// 通知遠程計算機登錄Internet
ShowMsg(hWin,"Call remote... ");
if ( StartCon( hWin,"connect","",
“d123","9W7607714" ) == TRUE )
{
ShowMsg(hWin,"Remote Connected");
// 取remote 分配的IP 地址
rip.dwSize=sizeof(RASPPPIP);
if ( (ret=RasGetProjectionInfo(hCon,RASP_PppIp,
(LPVOID) &rip,(LPDWORD) &ll ) ) != 0 )
ShowMsg(hWin,"取IP 地址失敗");
else
{
ShowMsg(hWin,rip.szIpAddress);
strcpy(szIp,rip.szIpAddress);
pdest=strrchr(szIp,'.');
*pdest='\0';strcat(szIp,".1");
ShowMsg(hWin,szIp);
SendCmd(szIp,"REQUEST");
}
RasHangUp(hCon);
}
else
ShowMsg(hWin,"Call remote fail");
hCon=NULL;
break;
case IDC_INTERNET:
// 本地計算機登錄Internet
ShowMsg(hWin,"正在連接Internet... ");
StartCon( hWin,"internet","local@pub2.fz.fj.cn",
"aabb99","9W163" );
break;
case IDC_ADDRESS:
// 讀取遠程計算機Internet IP 地址
ShowMsg(hWin,"正在取IP 地址...");
if ( (dwLen=FtpWriteRead("ftp.maoming.gd.cn",
"abc.txt",40,cRemoteIP,1))>0 )
{
cRemoteIP[dwLen]='\0';ShowMsg(hWin,cRemoteIP);
ShowMsg(hWin,"刪除IP 地址文件..");
MyFtpDeleteFile("ftp.maoming.gd.cn","abc.txt");
}
else
ShowMsg(hWin,"取IP 失敗");
break;
case IDC_RDISC:
// 通知遠程計算機斷開Internet 連接
ShowMsg(hWin,"正在向遠端發Disconnect...");
SendCmd(cRemoteIP,"DISCONNECT");
break;
}
ThreadId=0;hThread=NULL;
return;
}
// 遠程計算機運行線程函數
void ServerThread(void *pp )
{
RASPPPIP rip;
DWORD ret,ll;
SOCKADDR_IN aclearcase/" target="_blank" >cc_sin, dest_sin; // 地址
int acc_sin_len,status;
char szMsg[ MY_MSG_LENGTH ];
serv_sock = socket(AF_INET,SOCK_STREAM,0);
dest_sin.sin_family=AF_INET;
dest_sin.sin_addr.s_addr=INADDR_ANY;
dest_sin.sin_port=htons(1023);
bind(serv_sock,(struct sockaddr FAR *)
?。est_sin,sizeof(dest_sin));
listen(serv_sock,MAX_PENDING_CONNECTS);
while( TRUE )
{
acc_sin_len = sizeof(acc_sin);ShowMsg
(hWin,"等待呼叫");
rsock = accept( serv_sock,(struct sockaddr FAR *)
&acc_sin,(int FAR *) &acc_sin_len );
if (rsock < 0)
{ShowMsg(hWin,"Accept Error!");break;}
ShowMsg(hWin,"收到連接請求!");
status = recv( rsock, szMsg, MY_MSG_LENGTH,
NO_FLAGS_SET );
if (status == SOCKET_ERROR)
{ShowMsg(hWin,"Recv Error!");break;}
if (status)
{
szMsg[status] = '\0'; ShowMsg(hWin,szMsg);
if ( strstr(szMsg,"REQUEST") != NULL )
{
isend(rsock,"OK",2,0);
closesocket(rsock);Sleep(3000);
// 等待撥號連接退出
if (StartCon( hWin,"163","remote@pub2.fz.fj.cn",
"abcd","163" ) == TRUE )
{
// 取動態分配的IP 地址
rip.dwSize=sizeof(RASPPPIP);
if ( (ret=RasGetProjectionInfo(hCon,RASP_PppIp,
(LPVOID) &rip,(LPDWORD) &ll ) ) != 0 )
{ShowMsg(hWin,"取IP 地址失敗");break;}
ShowMsg(hWin,rip.szIpAddress);ShowMsg(hWin,
“Send IP Adrress.... !");
FtpWriteRead( "ftp.maoming.gd.cn","abc.txt",
strlen(rip.szIpAddress),rip.szIpAddress,0);
}
else
{ShowMsg(hWin,"Connect internet fail");}
}//if ( strstr(szMsg,"REQUEST") != NULL )
if ( strstr(szMsg,"DISCONNECT") != NULL )
{
send(rsock,"OK",2,0);
closesocket(rsock);RasHangUp(hCon);
} //end if ( strstr(szMsg,"DISCONNECT") != NULL )
} //end if (status)
else
{ShowMsg(hWin,"連接斷開! 等待下一個");
closesocket(rsock);}
} //end while( TRUE )
if(hCon != NULL )
{RasHangUp(hCon);Sleep(3000);}
hCon =NULL;closesocket(serv_sock);hThread=NULL;
return;
}
// 實現本地計算機向遠程計算機
發送命令的函數cIp 遠程計算機
IP 地址SzCmd 命令字符串
BOOL SendCmd(char *cIp,char *szCmd)
{
SOCKADDR_IN dest_sin; // 地址
int status;
char szMsg[ MY_MSG_LENGTH ];
rsock = socket(AF_INET,SOCK_STREAM,0);
dest_sin.sin_family=AF_INET;dest_sin.sin_
addr.s_addr = inet_addr(cIp);
dest_sin.sin_port=htons(1023);
if (connect( rsock,(PSOCKADDR)
&dest_sin,sizeof(dest_sin) )<0 )
{ShowMsg(hWin,"連接失敗");
closesocket( rsock );return FALSE;}
if ( send(rsock,szCmd,strlen(szCmd),0) != strlen(szCmd))
{ShowMsg(hWin,"送命令失敗");
closesocket( rsock );return FALSE;}
status = recv( rsock, szMsg, MY_MSG
_LENGTH, NO_FLAGS_SET );
if (status == SOCKET_ERROR)
{ShowMsg(hWin,"Recv Error!");
closesocket( rsock );return FALSE;}
szMsg[status] = '\0';
if ( status != 0 && strstr(szMsg,"OK") != NULL )
{closesocket( rsock );return TRUE;}
closesocket( rsock );return FALSE;
}