基于 Web 的拨号上网应用程序






4.91/5 (34投票s)
2003 年 6 月 30 日
2分钟阅读

204875

3579
一个用于连接和断开拨号上网会话的 Web 应用程序

引言
我最近更改了我的家庭网络,基本上是添加了一个服务器来将网络连接到互联网。不幸的是,我住的地方无法使用宽带互联网,因此互联网连接服务器需要拨号连接到我们的 ISP。我需要一种简单的方法来连接、断开连接并查看连接持续了多长时间。通常我会使用终端服务来建立和查看连接,但是由于我的妻子也使用互联网,所以我需要另一种更简单的方法,一种甚至我的妻子也可以使用的方法。我构建了这个 Web 应用程序,它显示当前连接的统计信息或显示电话簿条目,以便用户可以连接。
使用代码
我封装了一些 RAS API,以便我可以将它们与 P/Invoke 一起使用。 它们是
- RasEnumConnections
- RasGetConnectionStatistics
- RasHangUp
- RasEnumEntries
- InternetDial
我还必须创建一些这些 API 可以使用的结构
- RASCONN
- RasEntryName
- RasStats
我创建了一个简单的类,名为 RASDisplay,它具有以下方法和属性
方法
- int Connect(string Connection)
- void Disconnect()
属性
- bool IsConnected
- string ConnectionName
- double BytesReceived
- double BytesTransmitted
- string[] Connections
- string Duration
RASDisplay 类负责使用 RAS API 的所有复杂性。 如果您不熟悉使用 RAS API,则必须传入结构大小,以便 API 知道您正在使用的版本。 此类的构造函数使用以下代码来设置上述属性
private string m_duration;
private string m_ConnectionName;
private string[] m_ConnectionNames;
private double m_TX;
private double m_RX;
private bool m_connected;
private IntPtr m_ConnectedRasHandle;
public RASDisplay()
{
    m_connected = true;
    RAS lpras = new RAS();
    RASCONN lprasConn = new RASCONN();            
    lprasConn.dwSize = Marshal.SizeOf(typeof(RASCONN));
    lprasConn.hrasconn = IntPtr.Zero;
    int lpcb = 0;
    int lpcConnections = 0;
    int nRet = 0;
    lpcb = Marshal.SizeOf(typeof(RASCONN));
    nRet = RAS.RasEnumConnections(ref lprasConn, ref lpcb, 
                                         ref lpcConnections);
    if(nRet != 0)
    {
        m_connected = false;
        return;
    }
    if(lpcConnections > 0)
    {
        RasStats stats = new RasStats();
        m_ConnectedRasHandle = lprasConn.hrasconn;
        RAS.RasGetConnectionStatistics(lprasConn.hrasconn, stats);
        m_ConnectionName = lprasConn.szEntryName;
        //Work out our duration 
        int Hours = 0;
        int Minutes = 0;
        int Seconds = 0;
        //The RasStats duration is in milliseconds
        Hours = ((stats.dwConnectDuration /1000) /3600);
        Minutes = ((stats.dwConnectDuration /1000) /60) - 
                                              (Hours * 60);
        Seconds = ((stats.dwConnectDuration /1000)) - 
                           (Minutes * 60) - (Hours * 3600);
        m_duration = Hours  +  " hours "  + Minutes + 
                " minutes " + Seconds + " secs";
        //set the bytes transferred and received
        m_TX = stats.dwBytesXmited;
        m_RX = stats.dwBytesRcved;
    }
    else
    {
        //we aren't connected
        m_connected = false;
    }
    //Find the names of the connections we could dial
    int lpNames = 1;
    int entryNameSize=Marshal.SizeOf(typeof(RasEntryName));
    int lpSize=lpNames*entryNameSize;
    RasEntryName[] names=new RasEntryName[lpNames];
    for(int i=0;i<names.Length;i++)
    {
        names[i].dwSize=entryNameSize;
    }
    uint retval = RAS.RasEnumEntries(null,null,names,
                                 ref lpSize,out lpNames);
    m_ConnectionNames = new string[lpNames];
    if(lpNames>0)
    {                
        for(int i=0;i<lpNames;i++)
        {
            m_ConnectionNames[i] = names[i].szEntryName;
        }
    }
}
连接到互联网的代码使用 InternetDial WinInet API
public int Connect(string sConnection)
{
    int intConnection = 0;
    uint INTERNET_AUTO_DIAL_UNATTENDED = 2;
    int retVal = RAS.InternetDial(IntPtr.Zero, sConnection,
            INTERNET_AUTO_DIAL_UNATTENDED,ref intConnection,0);
    return retVal;
}
断开连接的代码也非常简单
public void Disconnect()
{
    RAS.RasHangUp(m_ConnectedRasHandle);
}
使用 RASDisplay 类的 Web 应用程序如下所示
protected System.Web.UI.WebControls.Label lblName;
protected System.Web.UI.WebControls.Label lblDuration;
protected System.Web.UI.WebControls.Label lblTransmitted;
protected System.Web.UI.WebControls.DataGrid dgAllConnections;
protected System.Web.UI.HtmlControls.HtmlTable tblCurrentConnection;
protected System.Web.UI.WebControls.Button btnDisconnect;
protected System.Web.UI.WebControls.Label lblRecieved;
private void Page_Load(object sender, System.EventArgs e)
{
    if(!IsPostBack)
    {
        BindData();
    }
}
private void BindData()
{
    try
    {
        RASDisplay display = new RASDisplay();
        lblName.Text = display.ConnectionName;
        lblDuration.Text = display.Duration;
        lblRecieved.Text = display.BytesReceived.ToString();
        lblTransmitted.Text = display.BytesTransmitted.ToString();
        if(!display.IsConnected)
        {
            //show the table with stats
            tblCurrentConnection.Visible = false;
        }
        else
        {
            //show the tables with available connections
            dgAllConnections.Visible = false;
        }
        //bind the data
        dgAllConnections.DataSource = display.Connections;
        dgAllConnections.DataBind();
    }
    catch(Exception e){
        Response.Write(e.Message);
    }
}
protected void btnConnect_Click(object sender, EventArgs e)
{
    RASDisplay rasDisplay = new RASDisplay();
    //need to find the text in the first column of the datagrid
    Button btnSender = (Button) sender;
    DataGridItem ob =  (DataGridItem) btnSender.Parent.Parent;
    int ErrorVal = rasDisplay.Connect(ob.Cells[1].Text);
    if(ErrorVal != 0)
    {
        Response.Write(ErrorVal);
    }
    else
    {
        //redirect to the same page, so the display 
        //is refreshed with stats
        Response.Redirect("Default.aspx");
    }
}
protected void btnDisConnect_Click(object sender, EventArgs e)
{
    RASDisplay rasDisplay = new RASDisplay();
    rasDisplay.Disconnect();
    //redirect to the same page, so the display is 
    //refreshed with available connections
    Response.Redirect("Default.aspx");
}
Web 应用程序具有一个 DataGrid,它显示机器上的所有连接,只有在计算机未连接到互联网时才会显示此 DataGrid。 否则,将显示包含连接统计信息的表格。 网页有一个 meta refresh 标签,以保持统计信息最新。
已知问题
目前,Connect 方法调用 InternetDial,此方法采用连接的名称。 如果此连接没有保存密码,则调用将失败。 在未来的版本中,我想更改应用程序连接到互联网的方式,也许使用 RASDial 并让应用程序存储用户的用户名和密码(或者要求他们输入?)
历史
- 文章创建时间:2003 年 6 月 30 日
- 更新于 2003 年 7 月 7 日 -只是一个 Bug 修复,如果用户有多个拨号上网电话簿,他们可能会遇到一些问题。
