首页 > Python基础教程 >
-
C#教程之C# 获取电脑的网络连接状态
判断连网的方法介绍
1. InternetGetConnectedState
- 此函数获取网络状态有延时,且对网卡伤害较大
- MSDN官方自己推荐不建议使用,不管是连网状态下还是断网情况下,获取的网络状态都有不准确的案例,如下:
(BUG) InternetGetConnectedState API returns false result
Detecting LAN connection using InternetGetConnectedState API doesn't work
https://stackoverflow.com/questions/14127810/check-internet-connection-with-internetgetconnectedstate-always-true
https://bbs.csdn.net/topics/340141699
在看下文之前,可以浏览MSDN:通过InternetGetConnectedState方法对网络状态的获取
如上InternetGetConnectedState方法介绍中
- dwReversed必须设置为0
- 通过输出值lpdwFlags可以获取当前网络连接的信息,通过拼装对比可以得到当前连接的网络类型,如拨号上网/局域网等
bool InternetGetConnectedState( out LPDWORD lpdwFlags, int dwReversed);
首先,添加非托管函数并调用,可以获取网络是否联网
//声明外部的函数
[DllImport("winInet.dll ")]
private static extern bool InternetGetConnectedState(ref int flag,int dwReserved);
2. IsNetworkAlive
需要服务System Event Notification的支持(系统默认自动启动该服务),且需要安装最新的SDK(如.NET)
浏览:MSDN对IsNetworkAlive的详细描述
由API中翻译:该功能可在Windows XP、2000(或Windows NT 4.0与Internet Explorer 5或更高版本)上使用,在windows95或更高版本上使用Internet Explorer 5或更高版本。所以,一般的系统都是支持的
输出值lpdwFlags
具体类型的详细内容可链接QOCINFO structure
- NETWORK_ALIVE_LAN=1 局域网(此处并非指有线网)
- NETWORK_ALIVE_WAN=2 远程访问-拨号访问和vpn访问(此处并非只无线网,按DPI所示,指的是RAS connections)
- NETWORK_ALIVE_AOL=4 无效的值。。。因为只有Win9x系统才有此第三个选项。参考链接
无线网络的判断:lpdwFlags对是否无线网络,并没有直接的判断。
eg:比如我的电脑环境(有线网络或者wifi网络),获取的flag=1(局域网)
返回值(bool)
- 当返回值为true,且无错误Code时,表示网络已连接
- 当返回值为false,且无错误Code时,表示网络未连接
那么,错误Code(异常)怎么获取呢?
3. 获取上一次异常Code-GetLastError
参考链接
此处推荐使用Marshal中的GetLastWin32Error,见如下源代码:
1 /// <summary>
2 /// 通过使用平台调用的最后一个非托管函数返回的错误代码返回调用具有 <see cref="F:System.Runtime.InteropServices.DllImportAttribute.SetLastError" /> 标志设置。
3 /// </summary>
4 /// <returns>最后一个错误代码设置通过调用 Win32 SetLastError 函数。</returns>
5 [SecurityCritical]
6 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
7 [MethodImpl(MethodImplOptions.InternalCall)]
8 public static extern int GetLastWin32Error();
GetLastWin32Error可获取最后一个非托管函数的错误Code
int errCode = Marshal.GetLastWin32Error();
--获取 error code的详细描述信息,可参考https://my.oschina.net/kavensu/blog/264273
值得注意的是,非托管函数声明时,要添加SetLastError=true;如:
1 [DllImport("sensapi.dll", SetLastError = true)]
2 private static extern bool IsNetworkAlive(out int connectionDescription);
4. 使用Ping函数
1 using (var ping = new Ping())
2 {
3 //ping给定的host 如:www.baidu.com,超时时间为1s
4 var reply = ping.Send(host, 1000);
5 var pingResult= reply != null && reply.Status == IPStatus.Success;
6 }
推荐判断电脑连接网络的方案
如上,获取网络状态是否连接,建议通过IsNetworkAlive函数获取。那么IsNetworkAlive是否准确呢?
答案是否!
案例:
- 电脑配置了虚拟机连接--断网后,IsNetworkAlive返回的是有网true !-- 对虚拟机等网络是否连接不能判断。
- 在某些情况下,光纤等坏了,上不了网络,但是走TCP协议可以聊微信QQ--IsNetworkAlive返回的是有网true !
无网络时,有可能返回有网:lpdwFlags=1 局域网时,如果当前配置了虚拟机连接之类的,本机无法连接网络时,IsNetworkAlive函数还是会返回true。如下:
所以,如果是局域网且IsNetworkAlive返回true,则使用InternetGetConnectedState重新获取网络状态。
1 //通过IsNetworkAlive方法,来获取电脑的联网状态 2 [DllImport("sensapi.dll", SetLastError = true)] 3 private static extern bool IsNetworkAlive(out int connectionDescription); 4 5 //通过InternetGetConnectedState方法,来获取电脑的联网状态 6 [DllImport("winInet.dll")] 7 private static extern bool InternetGetConnectedState(ref IntPtr dwFlag, int dwReserved); 8 9 /// <summary> 10 /// IsNetworkAlive函数输出值1-连接局域网 11 /// </summary> 12 private const int LanNetworkConnectedFlag = 1; 13 /// <summary> 14 /// 网络是否连接 15 /// </summary> 16 public static bool IsConnected 17 { 18 get 19 { 20 var isNetworkConnected = IsNetworkAlive(out int flags); 21 int errCode = Marshal.GetLastWin32Error(); 22 if (errCode != 0) 23 { 24 Console.WriteLine($"通过{nameof(IsNetworkAlive)}非托管DLL函数,获取网络状态时,遇到异常!"); 25 } 26 27 //IsNetworkAlive检测到是局域网连上网络,则使用InternetGetConnectedState重新确认是否有网 28 if (isNetworkConnected && flags == LanNetworkConnectedFlag) 29 { 30 var dwFlag = new IntPtr(); 31 isNetworkConnected = InternetGetConnectedState(ref dwFlag, 0); 32 errCode = Marshal.GetLastWin32Error(); 33 if (errCode != 0) 34 { 35 Console.WriteLine($"通过{nameof(InternetGetConnectedState)}非托管DLL函数,获取网络状态时,遇到异常!"); 36 } 37 } 38 39 return isNetworkConnected; 40 } 41 }
获取系统的网络状态与无线网的信号强度(格数)