您的位置:首页 > 编程语言 > Qt开发

再谈Qt实现Rasdial拨号问题(说说项目中遇到的问题和解决方案)

2017-12-01 13:10 453 查看
上一篇   Qt实现Rasdial宽带拨号  讲解了下最简单的宽带拨号方式。但是在实际项目开发中,发现,这种做法是不好的。效率低,有时拨号失败。而且上一回。我们是采用异步拨号来实现,这个做法是不行的。我们需要实现同步拨号。
那么我们应该借助api函数:   

DWORD   WaitForSingleObject( HANDLE
  hHandle, DWORD  dwMilliseconds);
    

以下是百度百科的解释,更详细的可以参考msdn

hHandle[in]对象句柄。可以指定一系列的对象,如Event、Job、Memory
resource notification、Mutex、Process、Semaphore、Thread、Waitable timer等。

dwMilliseconds[in]定时时间间隔,单位为milliseconds(毫秒).如果指定一个非零值,函数处于等待状态直到hHandle标记的对象被触发,或者时间到了。如果dwMilliseconds为0,对象没有被触发信号,函数不会进入一个等待状态,它总是立即返回。如果dwMilliseconds为INFINITE,对象被触发信号后,函数才会返回。

利用这个函数,我们可以实现同步拨号。但是这样做还不够,我们不能让这个可能耗时的操作来影响我们的gui线程。所以,我们需要把它放到单独一条线程运行。在这个线程里面实现断网和拨号。拨号后通知主线程就可以了。但是,我们需要检测拨号成功了没有。 好。进入第二个问题。

怎么判断当前网络是否运行连接成功? 第一做法就是查msdn。。然后找到了这个函数

[cpp] view
plain copy

BOOL InternetGetConnectedStateEx(  

  LPDWORD lpdwFlags,  

  LPTSTR lpszConnectionName,  

  DWORD dwNameLen,  

  DWORD dwReserved  

);  

具体的依然参考msdn library。我们这里只说下怎么判断宽带连接是否连接成功。按照msdn的说法。我们这样写就可以了。 bool ret = InternetGetConnectedStateExA
(0, “宽带连接”, 0, 0) .  只要判断下ret的bool值就可以了。用了几次后,我发现这样做根本就不靠谱呀。在企业开发中,有种比较常用的判断网络是否连接成功的方法是通过访问指定的外网和内网。公司的服务器上单独开一个接口用来判断。。捧着学习的态度,我决定用用别的api来解决。依然是借助api。这次我直接搜索RasDial。。结果,让我惊讶了下;。。真的有这个函数。通过这个函数可以直接拨号。为了追求效率,我决定放弃调用cmd命令,毕竟效率不高。我们来看下

[cpp] view
plain copy

DWORD RasDial(  

  LPRASDIALEXTENSIONS lpRasDialExtensions,  

  LPCTSTR lpszPhonebook,  

  LPRASDIALPARAMS lpRasDialParams,  

  DWORD dwNotifierType,  

  LPVOID lpvNotifier,  

  LPHRASCONN lphRasConn  

);  

老话,具体的请看msdn。总觉得这些api什么的,msdn已经讲解的很好了。这里给出qt如何使用这个函数。添加头文件 
#include <ras.h>   记得添加lib  #pragma comment(lib, "Rasapi32.lib");


[cpp] view
plain copy

bool MRasdial::reConnect()  

{  

    // 重新拨号函数  

    RASDIALPARAMS rasParam;  

    ZeroMemory(&rasParam, sizeof(RASDIALPARAMS));  

    rasParam.dwSize = sizeof (RASDIALPARAMS);  

    wcscpy(rasParam.szEntryName,L"ADSL" );  

    wchar_t userName[100] = L"", userPass[100] = L"";  

    m_UserName.toWCharArray(userName);  

    m_UserPass.toWCharArray(userPass);  

    wcscpy(rasParam.szUserName , userName);  

    wcscpy(rasParam.szPassword , userPass);  

  

    HRASCONN handle = NULL; // 注意,记得初始化。  

    int res = RasDial(0,0, &rasParam, 0, 0, &handle);  

  

    if (res != ERROR_SUCCESS) {  

  

        qDebug()<<"dial error:"<< res;  

  

        // 出错 采用断开连接的方法尝试再次连接  

        // 前提需要保障用户账号名和密码是正确的  

        RasHangUp (handle);  

        return false; // 返回错误 待会再连接  

    }  

  

    qDebug()<<"dial is over";  

    return true;  

}  

这边注意一个细节,我是怎么处理拨号出错的。为了防止宽带拨号处于宽带拨号中,我们需要借助 RasHangUp(HRASCONN handle); 来断开连接。。好了。现在回到第二个问题,该怎么判断网络连接状态。这个需要借助 RasEnumConnections 函数来枚举出当前连接的句柄信息。使用代码例子如下:

[cpp] view
plain copy

bool MRasdial::isADSLConnect()  

{  

    // 通过枚举获取当前连接的ADSL的句柄  

    RASCONN rasconnArr[20]; // 存放多个结构体  

    DWORD dwRasConSize =  20* sizeof(RASCONN);  

    DWORD dwRasConCount = 0;  

    rasconnArr[0].dwSize = sizeof (RASCONN);  

  

    if (!RasEnumConnections(rasconnArr, &dwRasConSize, &dwRasConCount)) {  

  

        for (int i =0; i< (int)dwRasConCount; ++i) {  

  

            if (wcscmp(rasconnArr[i].szEntryName, L"ADSL") == 0) {  

  

                return true;  

            }  

        }  

    }  

    return false;  

}  

这里我就是要判断当前连接是否有ADSL这个用户名。 这种做法就可以更好的判断当前用户名为ADSL的宽带账号是否连接成功。 最后,需要说明的是,在断开网络和连接网络,最好有一定的时间间隔。我的做法如下,仅供参考

[cpp] view
plain copy

void MRasdial::reConToNet()  

{  

    do {  

        disconnect(); // 断开网络  

        Sleep(4000);  

    } while (true == isADSLConnect());  

  

    qDebug()<<"net is dis";  

    // 连接网络  

    do {  

        if (true == reConnect())  

            break;  

        qDebug()<<"connect to net";  

        Sleep(4000);  

    } while (false == isADSLConnect());  

  

    emit reNetSuccess();  

}  

最后这里提供几个相关信息的链接:


关于RasDial拨号错误代码的详解: Routing and Remote Access Error Codes

关于拨号函数RasDial详解:  RasDial

from:http://blog.csdn.net/wu5151/article/details/47345399
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: