在程序中实现远程访问控制 作者:xrbeck
远程访问控制(Remote Access Service)是Windows NT,Win2000 Server提供的一种远程服务,它允许用户从远端通过拨号连接连接到一个本地的计算机网络,一旦建立了连接,就相当于处在了本地的LAN中,从而可以使用各种各样的网络函数以便进行访问,本文就是给大家介绍这种听起来就很动心的技术。 :) 首先我们需要配置服务器端的RAS服务,在这里以2k Server为例,第一安装modem,相信大家应该没什么问题吧.装好modem后,选择"控制面板"中的"网络和拨号连接",新建连接,选择"接受接入的连接",并且在最后一步添加一个允许登录的帐号,本文设置用户名:xr 密码:xr,这样就在服务器端建立了一个"等待接入"的连接,然后右键选择属性,在网络中选择TCP/IP协议,因为笔者的LAN中是通过代理,静态的分配保留IP地址172.18.所以在这个地方选择"指定TCP/IP地址"从'172.18.1.27“到"172.18.1.28"分配两个IP地址.这是因为VLSM是255.255.255.224,一个LAN中保留30台机器,选择后面几台未分配的IP地址。打开控制面板中的管理工具,选择路由和远程访问,选择本地服务器,并且"配置并启用路由和远程访问",可以查看活动与否的端口. 这样在服务器端就配置好了RAS服务.接下来进入关键部分:在远端用程序实现RAS连接.同样我们需要电话线和modem.安装好后我们就能利用系统提供的rasapi实现拨号连接. 以BCB5.0为例:给出源程序如下:1.连入头文件ras.h,raserror.h和库文件rasapi.lib 这个地方要注意有个版本冲突问题,所以需要临时的设置WINVER这个变量.具体代码如下:#define OLDVER WINVER#undef WINVER#define WINVER 0x400
#include <ras.h>#include <raserror.h>
#undef WINVER#define WINVER OLDVER#undef OLDVER静态连入rasapi.lib后,我们就能利用API函数实现拨号了
2. 拨接部分:void __fastcall TForm1::Button1Click(TObject *Sender){ // hrasconn=NULL; RASDIALPARAMS params; char buf[256]; memset(buf,0,256);
params.dwSize=sizeof(RASDIALPARAMS);
lstrcpy(params.szEntryName,""); lstrcpy(params.szPhoneNumber,"208"); lstrcpy(params.szUserName,"xr"); lstrcpy(params.szPassword,"xr"); lstrcpy(params.szDomain,"");
int ret=RasDial(NULL, NULL, ¶ms, 0, &RasDialFunc, &hrasconn); if(ret!=0) { RasGetErrorString(ret, buf, 256); memStatus->Lines->Add(buf);
}}其中RasDial为异步访问方式,208为笔者测试的公司内部的服务器的电话号码,xr是登录的用户名和口令,因为测试的2K Server是作为对等网中的普通一员,没有domain,所以设置为空.
3. 回调函数部分: 类似大部分的window程序,ras也提供了回调函数来异步的处理连接,这样的情况很多,比如Winsock也提供了窗口消息的异步方式.void WINAPI RasDialFunc(UINT MSG,RASCONNSTATE rasconnstate,DWORD dwError){ // char szRasString[256]; // Buffer for storing the error string memset(szRasString,0,256); DWORD cb=sizeof(RASPPPIP); DWORD ret;
if (dwError) // Error occurred { RasGetErrorString((UINT)dwError, szRasString, 256); Form1->memStatus->Lines->Add(szRasString); return; } switch (rasconnstate) { // Running States case RASCS_OpenPort: Form1->memStatus->Lines->Add("Opening port..."); break;
case RASCS_PortOpened: Form1->memStatus->Lines->Add("Port opened."); break;
case RASCS_Authenticated: Form1->memStatus->Lines->Add("Authentication complete."); break;
case RASCS_Connected: Form1->memStatus->Lines->Add("Connection Connected.");
Form1->lpProjection=new RASPPPIP; Form1->lpProjection->dwSize=sizeof(RASPPPIP); if(RasGetProjectionInfo(Form1->hrasconn,RASP_PppIp,Form1->lpProjection,&cb)==ERROR_SUCCESS) { Form1->memStatus->Lines->Add("Server IP:"+(AnsiString)(Form1->lpProjection->szServerIpAddress)); Form1->memStatus->Lines->Add("Local IP:"+(AnsiString)(Form1->lpProjection->szIpAddress)); } break;
case RASCS_Disconnected: Form1->memStatus->Lines->Add("Disconnecting..."); break;
default: Form1->memStatus->Lines->Add("Unknown Status "); break; }} 处理各种消息,其中在连接部分使用RasGetProjectionInfo得到连接分配的IP地址和服务器端的地址.由于是静态的分配的,所以和服务器端是处于一个子网当中,也就能使用各种各样的资源了,比如说可以使用WNET系列函数得到LAN中的情况,又或者在Connect事件后建立套接字,实现传输.笔者测试如下:拔掉客户端的网线后,建立连接后能ping到LAN中其他的机器,而且由于处于子网中,所以也能上网了,使用IPHelper函数返回的子网掩码和网关是一致的.
本文为大家介绍了什么是RAS以及如何编程实现RAS服务,无疑这是一项方便而强大的功能.希望能给大家带来帮助.也欢迎大家进一步继续讨论.QQ.33854303
测试环境: 客户端BCB5.0+Win98. 服务器端:Win2000 Server 参考书籍: Windows网络编程 Internet与TCP/IP程序设计之C++ Builder高手