gpt4 book ai didi

C# 循环中的多次 ping

转载 作者:行者123 更新时间:2023-12-01 23:52:49 25 4
gpt4 key购买 nike

我需要创建将循环 ping 多个地址的应用程序。我在 stackoverflow 上阅读了很多示例,终于得到了工作代码:

    public void Check(List<string> addresses)
{
List<Task<PingReply>> pingTasks = new List<Task<PingReply>>();
foreach (string address in addresses)
{
pingTasks.Add(PingAsync(address));
}

Task.Factory.ContinueWhenAll(pingTasks.ToArray(), _ => { }).ContinueWith(t =>
{
StringBuilder pingResult = new StringBuilder();
foreach (var pingTask in pingTasks)
{
pingResult.Append(pingTask.Result.Address);
pingResult.Append(" ");
pingResult.Append(pingTask.Result.Status);
pingResult.Append(" ");
pingResult.Append(pingTask.Result.RoundtripTime.ToString());
pingResult.Append(" \n");
}
Console.WriteLine(pingResult.ToString());
},
CancellationToken.None,
TaskContinuationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext());
}

public static Task<PingReply> PingAsync(string address)
{
var tcs = new TaskCompletionSource<PingReply>();
using (Ping ping = new Ping())
{
ping.PingCompleted += (obj, sender) =>
{
tcs.SetResult(sender.Reply);
};
ping.SendAsync(address, new object());
}
return tcs.Task;
}

现在我需要更改此代码以与等待和异步一起使用,然后按时间间隔循环执行此代码。我的问题就从这里开始了。我不知道在这种情况下如何使用异步,我读了很多文章,现在我很困惑,因为我的代码仍然无法工作。您能逐步解释一下如何更改我的代码以与等待一起使用吗?你能解释一下如何将它放入 while 循环中并执行间隔吗?我尝试将整个“Check”函数放入循环中并在最后添加 Thread.Sleep(interval) 但我有一种奇怪的感觉,我做错了/效率低下的事情。我需要在 1 秒内 ping 400 个服务器。有可能吗?问候

更新1:到目前为止我有代码:

using System;
using System.Collections.Generic;
using System.IO;
using System.Web;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Net.NetworkInformation;
using System.Linq;

namespace Pinging
{
class CheckPing
{
public async Task LoopAndCheckPingAsync(List<string> addresses)
{
while (true)
{
var ping = new Ping();
var pingTasks = addresses.Select(address => ping.SendPingAsync(address));

await Task.WhenAll(pingTasks);

StringBuilder pingResultBuilder = new StringBuilder();

foreach (var pingReply in pingTasks)
{
pingResultBuilder.Append(pingReply.Result.Address);
pingResultBuilder.Append(" ");
pingResultBuilder.Append(pingReply.Result.Status);
pingResultBuilder.Append(" ");
pingResultBuilder.Append(pingReply.Result.RoundtripTime.ToString());
pingResultBuilder.AppendLine();
}

Console.WriteLine(pingResultBuilder.ToString());

await Task.Delay(TimeSpan.FromMinutes(5));
}
}
}
}

并调用:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Pinging
{
public class Class1
{
static void Main()
{
List<string> addresses = new List<string>() { "www.google.pl", "212.77.100.101" };

CheckPing c = new CheckPing();
Task.Factory.StartNew(() => c.LoopAndCheckPingAsync(addresses));

Console.Read();
}
}
}

我尝试用不同的方式从 Main 调用 LoopAndCheckPingAsync,但仍然卡住。这是我最后一次尝试。

编辑2:我做了一些更改来查看应用程序性能,现在我的代码如下所示:

using System;
using System.Collections.Generic;
using System.IO;
using System.Web;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Net.NetworkInformation;
using System.Linq;

namespace Pinging
{
class CheckPing
{
public async Task LoopAndCheckPingAsync(List<string> addresses)
{
while (true)
{
var pingTasks = addresses.Select(address =>
{
return new Ping().SendPingAsync(address);
});

await Task.WhenAll(pingTasks);

StringBuilder pingResultBuilder = new StringBuilder();

foreach (var pingReply in pingTasks)
{
pingResultBuilder.Append(pingReply.Result.Address);
pingResultBuilder.Append(" ");

pingResultBuilder.Append(pingReply.Result.Status);
pingResultBuilder.Append(" ");

pingResultBuilder.Append(pingReply.Result.RoundtripTime.ToString());
pingResultBuilder.AppendLine();
}

Console.WriteLine(pingResultBuilder.ToString());
Functions.counter++;

if (Functions.counter >= 100) break;

await Task.Delay(TimeSpan.FromSeconds(1));
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Pinging
{
public class Class1
{
static void Main()
{
List<string> addresses = Functions.Read(@"C:\Users\Adam\Desktop\addresses.csv");

Functions.start = DateTime.Now;

CheckPing c = new CheckPing();
c.LoopAndCheckPingAsync(addresses).Wait();

Console.WriteLine(Functions.counter);

Console.Read();
}
}
}

我正在使用从文件中读取的标准站点地址:

www.google.com
www.yahoo.com
www.live.com
www.msn.com
www.facebook.com
www.youtube.com
www.microsoft.com
www.wikipedia.org
www.myspace.com
www.ebay.com
www.aol.com
www.ask.com
www.craigslist.org
www.blogspot.com
www.answers.com
www.about.com
www.amazon.com
www.mapquest.com
www.windows.com
www.adobe.com
www.photobucket.com
www.wordpress.com
www.go.com
www.paypal.com
www.walmart.com
www.reference.com
www.cnn.com
www.twitter.com
www.imdb.com
www.flickr.com
www.att.com
www.cnet.com
www.irs.gov
www.whitepages.com
www.yellowpages.com
www.comcast.net
www.target.com
www.simplyhired.com
www.webmd.com
www.weather.com
www.blogger.com
www.bankofamerica.com
www.apple.com
www.chase.com
www.bizrate.com
www.hulu.com
www.merriam-webster.com
www.geocities.com
www.ehow.com
www.ezinearticles.com

编辑3:现在一切都很完美,但这是我需要处理的另一个问题。当我在 5 分钟后测试 100000 ping 时,出现内存不足异常。有办法以某种方式处理这个问题吗?也许分成 block 并销毁旧类?

编辑4:错误内容:

System.OutOfMemoryException was unhandled HResult=-2147024882 Message=Exception of type 'System.OutOfMemoryException' was thrown. Source=mscorlib StackTrace: at System.Exception.Init() at System.InvalidOperationException..ctor(String message, Exception innerException) at System.Net.NetworkInformation.PingException..ctor(String message, Exception innerException) at System.Net.NetworkInformation.Ping.ContinueAsyncSend(Object state) at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() at System.Threading.ThreadPoolWorkQueue.Dispatch() at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
InnerException:

编辑 5 添加 using 语句后,我收到“没有足够的存储空间可用于处理此命令”错误:

System.AggregateException was unhandled HResult=-2146233088
Message=One or more errors occurred. Source=mscorlib StackTrace: at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions) at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken) at System.Threading.Tasks.Task.Wait() at Pinging.Class1.Main() at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart() InnerException: System.Net.NetworkInformation.PingException HResult=-2146233079 Message=An exception occurred during a Ping request. Source=mscorlib StackTrace: at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() at Pinging.CheckPing.d__2.MoveNext() InnerException: System.ApplicationException HResult=-2147024888 Message=Not enough storage is available to process this command (Exception from HRESULT: 0x80070008) Source=mscorlib StackTrace: at System.Threading.ThreadPool.RegisterWaitForSingleObjectNative(WaitHandle waitHandle, Object state, UInt32 timeOutInterval, Boolean executeOnlyOnce, RegisteredWaitHandle registeredWaitHandle, StackCrawlMark& stackMark, Boolean compressStack) at System.Threading.ThreadPool.RegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callBack, Object state, UInt32 millisecondsTimeOutInterval, Boolean executeOnlyOnce, StackCrawlMark& stackMark, Boolean compressStack) at System.Threading.ThreadPool.RegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callBack, Object state, Int32 millisecondsTimeOutInterval, Boolean executeOnlyOnce) at System.Net.NetworkInformation.Ping.InternalSend(IPAddress address, Byte[] buffer, Int32 timeout, PingOptions options, Boolean async) at System.Net.NetworkInformation.Ping.ContinueAsyncSend(Object state) InnerException:

最佳答案

让我们看看我们想要做什么:

  1. 我们希望在第一次执行该方法时开始 while 循环

  2. 我们想要生成一堆用于发送 ping 请求的任务。为此,我们可以使用 Ping.SendPingAsync 。我们将使用 Enumerable.Select 投影地址列表中的每个元素。

  3. 我们将等待所有任务完成执行。为此,我们将 await Task.WhenAll .

  4. 当所有任务完成执行 ping 请求时,我们将使用 foreach 迭代它们。循环。

  5. 我们将等待调用之间的间隔时间。我们不会使用Thread.Sleep ,因为这是一个阻塞调用。我们将改为使用 Task.Delay 将在内部使用 Timer 。当我们等待它时,控制权将返回给调用我们的方法。

结果是这样的:

private static async Task LoopAndCheckPingAsync(List<string> addresses)
{
StringBuilder pingResultBuilder = new StringBuilder();

while (true)
{
var pingTasks = addresses.Select(address =>
{
using (var ping = new Ping())
{
return ping.SendPingAsync(address);
}
}).ToList();

await Task.WhenAll(pingTasks);

foreach (var pingReply in pingTasks)
{ pingResultBuilder.Append(pingReply.Result.Address);
pingResultBuilder.Append(" ");
pingResultBuilder.Append(pingReply.Result.Status);
pingResultBuilder.Append(" ");

pingResultBuilder.Append(pingReply.Result.RoundtripTime.ToString());
pingResultBuilder.AppendLine();
}

Console.WriteLine(pingResultBuilder.ToString());
pingResultBuilder.Clear();

await Task.Delay(TimeSpan.FromMinutes(5));
}
}

请注意,该方法现在返回 Task而不是void ,因为我们需要await在我们的方法上(注意 async 一旦您开始使用它,就会在您的代码库中传播)。

编辑

深入研究 Ping class 后,显然我们无法在同一个 Ping 上执行多个 ping 请求实例(查看 Ping.CheckStart 它检查是否有正在进行的请求,如果有则抛出 InvalidOperationException ),这正是我们在 Select 中所做的方法。为了解决这个问题,我们可以创建 Ping 的实例。每个请求的类。请注意,这会给您的应用程序增加一些内存压力。如果您有 1000 个并发请求,则意味着您将拥有 1000 个 Ping 实例。发出这些请求时内存中的类。

另一件事需要注意的是,您正在一个控制台应用程序中运行,该应用程序在内部使用 ThreadPoolSynchronizationContext。无需调用Task.Run要执行我们的方法,您可以使用 Task.Wait在发出请求时保持控制台应用程序处于事件状态。最好使用Wait ,这样我们就可以查看是否有任何异常从我们的方法传播。

static void Main()
{
List<string> addresses = new List<string>() { "www.google.pl", "212.77.100.101" };

CheckPing c = new CheckPing();
c.LoopAndCheckPingAsync(addresses).Wait();
}

关于C# 循环中的多次 ping,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25449486/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com