本文提出采用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 acc_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 *)
&dest_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;
}
>> 本文固定链接: http://www.vcgood.com/archives/640