如何使用 C# 检测互联网何时空闲(无下载/上传),并在空闲时启动下载?
1 回答
如果您正在等待没有连接的时刻……您必须知道即使您认为自己没有使用 Internet,也有很多连接。
尝试查看WireShark和Prcomon(来自 sysitnerals)以了解想法。
网络流量
注意:如果您通过 Mono 在 Mac 或 Linux 上使用 .NET,您应该知道此 API 不能很好地移植到其他操作系统。因此,我在这里描述的仅适用于 Windows。
如果您想要了解流量,您可以尝试使用System.Net.NetworkInformation.IPGlobalStatistics。
你可以这样做,像这样:
var properties = IPGlobalProperties.GetIPGlobalProperties();
// IPGlobalStatistics for IPv4
var ipv4stat = properties.GetIPv4GlobalStatistics();
// IPGlobalStatistics for IPv6
var ipv6stat = properties.GetIPv6GlobalStatistics();
从MSDN 的示例:
Console.WriteLine(" Forwarding enabled ...................... : {0}",
ipstat.ForwardingEnabled);
Console.WriteLine(" Interfaces .............................. : {0}",
ipstat.NumberOfInterfaces);
Console.WriteLine(" IP addresses ............................ : {0}",
ipstat.NumberOfIPAddresses);
Console.WriteLine(" Routes .................................. : {0}",
ipstat.NumberOfRoutes);
Console.WriteLine(" Default TTL ............................. : {0}",
ipstat.DefaultTtl);
Console.WriteLine("");
Console.WriteLine(" Inbound Packet Data:");
Console.WriteLine(" Received ............................ : {0}",
ipstat.ReceivedPackets);
Console.WriteLine(" Forwarded ........................... : {0}",
ipstat.ReceivedPacketsForwarded);
Console.WriteLine(" Delivered ........................... : {0}",
ipstat.ReceivedPacketsDelivered);
Console.WriteLine(" Discarded ........................... : {0}",
ipstat.ReceivedPacketsDiscarded);
Console.WriteLine(" Header Errors ....................... : {0}",
ipstat.ReceivedPacketsWithHeadersErrors);
Console.WriteLine(" Address Errors ...................... : {0}",
ipstat.ReceivedPacketsWithAddressErrors);
Console.WriteLine(" Unknown Protocol Errors ............. : {0}",
ipstat.ReceivedPacketsWithUnknownProtocol);
Console.WriteLine("");
Console.WriteLine(" Outbound Packet Data:");
Console.WriteLine(" Requested ........................... : {0}",
ipstat.OutputPacketRequests);
Console.WriteLine(" Discarded ........................... : {0}",
ipstat.OutputPacketsDiscarded);
Console.WriteLine(" No Routing Discards ................. : {0}",
ipstat.OutputPacketsWithNoRoute);
Console.WriteLine(" Routing Entry Discards .............. : {0}",
ipstat.OutputPacketRoutingDiscards);
Console.WriteLine("");
Console.WriteLine(" Reassembly Data:");
Console.WriteLine(" Reassembly Timeout .................. : {0}",
ipstat.PacketReassemblyTimeout);
Console.WriteLine(" Reassemblies Required ............... : {0}",
ipstat.PacketReassembliesRequired);
Console.WriteLine(" Packets Reassembled ................. : {0}",
ipstat.PacketsReassembled);
Console.WriteLine(" Packets Fragmented .................. : {0}",
ipstat.PacketsFragmented);
Console.WriteLine(" Fragment Failures ................... : {0}",
ipstat.PacketFragmentFailures);
Console.WriteLine("");
可以上网吗?
如果您需要在 Internet 可用时收到通知,您可以订阅System.Net.NetworkInformation.NetworkChange。网络可用性已更改。这样,如果 Internet 连接或断开连接,您将收到通知事件(不要忘记取消订阅)。
例子:
var handler = new NetworkAddressChangedEventHandler
(
(sender, args) =>
{
//handle notification
}
);
System.Net.NetworkInformation.NetworkChange += handler;
// Unsubscribe:
System.Net.NetworkInformation.NetworkChange -= handler;
您可能有兴趣了解哪些网络适配器是 Up 或 Down 以及每个适配器有多少流量......请参见下文。
空闲和空闲时间
让我们定义“空闲”。我会说“空闲”意味着互联网可用(请检查上面),并且如果它没有在给定的时间内使用。
因此,您要做的另一件事是调用NetworkInterface.GetAllNetworkInterfaces ,它将为您提供一个System.Net.NetworkInformation.NetworkInterface数组,您可以在该数组上调用GetIPStatistics方法来获取该特定网络接口的 IPStatistics 对象。您还可以阅读OperationalStatus属性以了解特定接口是否已启动
例子:
NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces();
foreach (var adapter in adapters)
{
// Is Up, Down, something else?
Console.WriteLine(" {0} is {1}", adapter.Name, dapter.OperationalStatus);
var stats = adapter.GetIPStatistics();
// Read some properties
Console.WriteLine(" Bytes Recieved: {0}", stats.BytesReceived);
Console.WriteLine(" Bytes Sent: {0}", stats.BytesSent);
}
您需要做的是以您可以查询的方式存储此信息,以检查它是否已更改:
// Fields
Dictionary<string, Tuple<long, long>> data
= new Dictionary<string, Tuple<long, long>>();
bool IsInternetIdle()
{
bool idle = true;
NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces();
foreach (var adapter in adapters)
{
var stats = adapter.GetIPStatistics();
Tuple<long, long> info;
if (!data.TryGetValue(adapter.Name, out info))
{
//New Adapter
info = new Tuple<long, long>
(
stats .BytesReceived,
stats .BytesSent
);
data.Add(adapter.Name, info);
}
else
{
if
(
info.Item1 != stats .BytesReceived
|| info.Item2 != stats .BytesSent
)
{
idle = false;
break;
}
}
}
//Console.WriteLine("Is Idle: {0}", idle.ToString());
return idle;
}
并添加一些逻辑来处理空闲时间:
// Fields
Stopwatch watch = new Stopwatch();
static TimeSpan? GetInternetIdleTime()
{
if (IsInternetIdle())
{
if (!watch.IsRunning)
{
watch.Start();
}
//Console.WriteLine("Idle Time: {0}", XmlConvert.ToString(watch.Elapsed));
return watch.Elapsed;
}
else
{
watch.Stop();
watch.Reset();
return null;
}
}
示例用法:
GetInternetIdleTime(); //preemptive call
Thread.Sleep(1000);
var result = GetInternetIdleTime();
if (result.HasValue)
{
Console.WriteLine("Idle time: {0}", result.Value);
}
else
{
Console.WriteLine("Not Idle");
}
Console.ReadKey();
小心的话
- 请记住取消订阅您的事件处理程序。
- 这仅适用于 Windows。
- 请记住,第一次运行
IsInternetIdle
(如上所述)所有网络适配器都是新的。在声明使用它们之前,您可能想要先发制人地调用GetInternetIdleTime
(如上所述)。 - 这些方法
IsInternetIdle
和GetInternetIdleTime
旨在仅在 Internet 可用时使用。您可以添加检查以查看各个网络适配器是否已启动。 - 上述结果
GetInternetIdleTime
不是连接处于非活动状态的总时间,而是自发现连接处于非活动状态以来的时间。您可能想要调用GetInternetIdleTime
一个计时器(如果您的应用程序有一个主循环 - 比如说,这是一个游戏 - 您可以以给定的频率调用它)。 - 如果一个 netwokr 适配为 Active,并不意味着它正在使用Internet。也许它连接到一些Intranet。无法判断“Internet”是否可以访问。您应该自己检查与各个服务器的连通性。不知道要检查什么?这可能会出现问题,因为 DNS 可以在本地被覆盖……但您可以尝试example.or、InterNIC.net甚至ntp.ord。
选择
由于无论如何这都是针对 Windows 的,您可以尝试使用WMI来获取网络适配器信息,为此我将向您推荐 Mladen Prajdic 的Find only physical network adapters with WMI Win32_NetworkAdapter class。
深层发掘
您可以使用PCapDotNet模拟 WireShark 所做的事情,您可以在CodeProject.com找到示例。让我DuckDuckGo给你。