我想实现如下图的效果,同时Ping几个IP,显示每个IP的Ping结果:
我把我的测试结果是显示在datagridview中的,一个IP的Ping信息用一行显示。
我之前测试过只Ping一个IP,没什么问题,但是我加了个for,开启几个线程,没个线程Ping一个IP,就不行了。会报错误,
错误提示是:“System.ArgumentOutOfRangeException”类型的未经处理的异常在 System.Windows.Forms.dll 中发生
其他信息: 索引超出范围。必须为非负值并小于集合大小。我定义的iprecord变量的值变成了3,但是我限定的条件是iprecord是小于IP数组Iptotal的长度的,Iptotal的长度就是3。我的VS有点问题,打不了断点,开不到中断信息,点击中断软件就自动关闭了。就只能把信息贴出来。
public void MethodRandomBytesTrue(string[] IP, string istesttime, string istestcount, string maxbuffer, string internaltime, string icmpcount)
{
if (istesttime == "False" && istestcount == "False")
{
Thread threadmethod = null;
for (int iprecord = 0; iprecord < IP.Length; iprecord++)
{
threadmethod = new Thread(new ThreadStart (delegate
{
DateTime t1 = DateTime.Now;
Ping p = new Ping();
PingReply reply;
PingOptions options = new PingOptions();
options.DontFragment = true;
System.Random randomnum = new Random();//定义一个随机数
int maxbuffernum = Convert.ToInt32(maxbuffer);//用于产生一个随机字节数
byte[] buffer;
FlagNetTest = true;
int successcount = 0;
int failcount = 0;
int icmptotal = 0;
int throwcount = 0;
int maxtime = 0;
int mintime = 0;
int avetime = 0;
int time = Convert.ToInt32(internaltime);
Thread.Sleep(10);
DateTime t2 = DateTime.Now;
while (FlagNetTest)
{
t2 = DateTime.Now;
//更新Ping测时间
dataGridView1.Invoke((MethodInvoker)delegate
{
dataGridView1.Rows[iprecord].Cells[1].Value = ((t2 - t1).TotalSeconds).ToString("0.00") + " 秒";
});
Thread.Sleep(time);//设置刷新时间.
icmptotal++;
dataGridView1.Invoke((MethodInvoker)delegate
{
dataGridView1.Rows[iprecord].Cells[2].Value = (icmptotal - 1).ToString();
dataGridView1.Rows[iprecord].Cells[7].Value = (100 * (float)(icmptotal - 1) / (t2 - t1).TotalSeconds).ToString("0.00") + " 包/秒";
});
buffer = new byte[randomnum.Next(0, maxbuffernum)];
reply = p.Send(IP[iprecord], 1500, buffer);
if (reply.Status == IPStatus.Success)
{
successcount++;
this.BeginInvoke(new invokedelegate1(UpdatetxtPingSesults), "\n来自 " + reply.Address + " 的回复: [ 字节:" + reply.Buffer.Length + " 往返时间:" + reply.RoundtripTime + "ms TTL(生存时间):" + reply.Options.Ttl + " ]\n");
dataGridView1.Invoke((MethodInvoker)delegate
{
dataGridView1.Rows[iprecord].Cells[3].Value = successcount.ToString();
});
}
else if (reply.Status == IPStatus.TimedOut)
{
this.BeginInvoke(new invokedelegate1(UpdatetxtPingSesults), "\nTimesOut\n");
successcount++;
dataGridView1.Invoke((MethodInvoker)delegate
{
dataGridView1.Rows[iprecord].Cells[3].Value = successcount.ToString();
});
}
else if (reply.Status == IPStatus.SourceQuench)
{
throwcount++;
this.BeginInvoke(new invokedelegate1(UpdatetxtPingSesults), "\n已丢失数据包\n");
dataGridView1.Invoke((MethodInvoker)delegate
{
dataGridView1.Rows[iprecord].Cells[5].Value = throwcount.ToString();
dataGridView1.Rows[iprecord].Cells[6].Value = (100 * (float)throwcount / (icmptotal - 1)).ToString("0.00") + "%";//更新丢包率
});
}
else
{
failcount++;
this.BeginInvoke(new invokedelegate1(UpdatetxtPingSesults), "\n目标计算机无法访问\n");
dataGridView1.Invoke((MethodInvoker)delegate
{
dataGridView1.Rows[iprecord].Cells[4].Value = failcount.ToString();
});
}
dataGridView1.Invoke((MethodInvoker)delegate
{
dataGridView1.Rows[iprecord].Cells[2].Value = icmptotal.ToString();
});
if (!roundtriptime.Contains(Convert.ToInt32(reply.RoundtripTime)))
{
roundtriptime.Add(Convert.ToInt32(reply.RoundtripTime));
Thread.Sleep(10);
maxtime = roundtriptime.Max();
mintime = roundtriptime.Min();
avetime = (int)roundtriptime.Average();
dataGridView1.Invoke((MethodInvoker)delegate
{
dataGridView1.Rows[iprecord].Cells[8].Value = maxtime.ToString() + "/" + mintime.ToString() + "/" + avetime.ToString() + " 毫秒";
});
}
}
}));
threadmethod.Start();
}
}
但是我采用
for (int iprecord = 0; iprecord < IP.Length; iprecord++)
{
MessageBox(iprecord.ToString());
}
看iprecord的值变化,又是正常的。
为何我加上线程后,iprecord就超出限定了。
------解决思路----------------------
当你的线程在运行的时候iprecord不知道变成几了,当然会出错
------解决思路----------------------
你开启的多线程 又使用同一个对象..能不乱么 - - .
------解决思路----------------------
业务逻辑和UI完全混在了一起,不出错才怪。试着把业务逻辑分离出来封装到单独的类里,通过事件通知界面进行变化,相信你的问题自然会被解决的。
------解决思路----------------------
闭包问题
不要用匿名函数
写个线程函数执行
参数全部传入
不要用全局变量
------解决思路----------------------
for (int iprecord = 0; iprecord < IP.Length; iprecord++)
{
int iprecord2 = iprecord;
.................