C#实现网络小程序的步骤详解
作者:dawn
经常要检测某些IP地址范围段的计算机是否在线。
有很多的方法,比如进入到网关的交换机上去查询、使用现成的工具或者编写一个简单的DOS脚本等等,这些都比较容易实现。
现在使用C#来完成。
1、简单上手
公用函数:
public static long IPToLong(string ip) { //将IP地址转换为长整数 string[] ipBytes = ip.Split('.'); long ipLong = 0; ipLong += long.Parse(ipBytes[0]) * 256 * 256 * 256; ipLong += long.Parse(ipBytes[1]) * 256 * 256; ipLong += long.Parse(ipBytes[2]) * 256; ipLong += long.Parse(ipBytes[3]); return ipLong; } public static string LongToIP(long ip) { //将长整数IP地址转换为实际的IP地址 long ipLong = ip; string ipString = string.Empty; ipString += ipLong / 256 / 256 / 256 + "."; ipLong = ipLong % (256 * 256 * 256); ipString += ipLong / 256 / 256 + "."; ipLong = ipLong % (256 * 256); ipString += ipLong / 256 + "."; ipLong = ipLong % 256; ipString += ipLong; return ipString; }
点击【检测】按钮:
DateTime startTime, endTime; startTime= DateTime.Now; listBox1.Items.Add(startTime.ToString()); string startIP = textBox1.Text; string endIP = textBox2.Text; // 将起始IP地址和结束IP地址转换为长整数 long startIPLong = IPToLong(startIP); long endIPLong = IPToLong(endIP); Ping ping = new Ping(); // 遍历IP地址范围 for (long i = startIPLong; i <= endIPLong; i++) { // 将整数转换为IP地址 string ip = LongToIP(i); // 输出 PingReply pingReply = ping.Send(ip); if (pingReply.Status == IPStatus.Success) { listBox1.Items.Add( ip + "=>计算机在线"); } else { listBox1.Items.Add(ip); } } endTime = DateTime.Now; listBox1.Items.Add(endTime.ToString()); listBox1.Items.Add("OK:" + (endTime - startTime).ToString());
执行时没有问题的,可以出来结果,问题是界面卡顿了。
执行的时间也很长,执行需要1分21秒。
这个结果不能接受,需要对程序加以改进。
2、使用并行计算
不需要改动公用代码,只需要改动检测部分。
Dictionary<string, string> ipResults = new Dictionary<string, string>(); DateTime startTime, endTime; startTime = DateTime.Now; listBox1.Items.Add(startTime.ToString()); string startIP = textBox1.Text; string endIP = textBox2.Text; // 将起始IP地址和结束IP地址转换为整数 long startIPLong = IPToLong(startIP); long endIPLong = IPToLong(endIP); // 创建一个可以存储IP地址的List List<string> ipList = new List<string>(); for (long i = startIPLong; i <= endIPLong; i++) { // 将整数转换为IP地址 string ip = LongToIP(i); ipList.Add(ip); ipResults.Add(ip,""); listBox1.Items.Add(ip); } // 开启并行计算 Parallel.ForEach(ipList, (ip) => { // 创建一个新的Ping类 Ping pingSender = new Ping(); // 发送一个Ping请求 var reply = pingSender.Send(ip); // 如果返回的状态是Success,则IP地址在线 if (reply.Status == IPStatus.Success) { ipResults[ip] = "在线"; ChangeIPStatus(ip,"在线"); } else { ipResults[ip] = "NO"; ChangeIPStatus(ip, "NO"); } }); endTime = DateTime.Now; listBox1.Items.Add(endTime.ToString()); listBox1.Items.Add("OK:" + (endTime - startTime).ToString());
增加一个公用函数:
public void ChangeIPStatus(string ip,string S1) { // 定位到listbox中记录并更改IP是否在线 int index = listBox1.Items.IndexOf(ip); listBox1.Items[index] = ip+" "+S1; }
出现问题:
⑴ 提示“C#线程间操作无效:从不是创建控件“textbox1”的线程访问它”,这个就简单设置Control.CheckForIllegalCrossThreadCalls=false即可解决;
⑵ 提示“listbox1包含的项太多”,这个是不是与并行计算开启的线程太多有关?考虑到本机是8核,保守一点,修改参数
Parallel.ForEach(ipList, new ParallelOptions() { MaxDegreeOfParallelism = MaxDegreeOfParallelism = Environment.ProcessorCount }, (ip) => { //执行代码 }
程序可以正常运行了。
⑶ 界面依然阻塞,但用时更多了。
去ping255个地址,竟然用了12分32秒!!!这个真是不可忍受,最关键没有界面交互,这太不用户友好了!
3、添加异步编程
Dictionary<string, string> ipResults = new Dictionary<string, string>(); DateTime startTime, endTime; startTime = DateTime.Now; listBox1.Items.Add(startTime.ToString()); string startIP = textBox1.Text; string endIP = textBox2.Text; // 将起始IP地址和结束IP地址转换为整数 long startIPLong = IPToLong(startIP); long endIPLong = IPToLong(endIP); // 创建一个可以存储IP地址的List List<string> ipList = new List<string>(); for (long i = startIPLong; i <= endIPLong; i++) { // 将整数转换为IP地址 string ip = LongToIP(i); ipList.Add(ip); ipResults.Add(ip,""); listBox1.Items.Add(ip); } Task task = new Task(() => { // 创建一个多线程 Parallel.ForEach(ipList, new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount }, (ip) => { // 创建一个新的Ping类 Ping pingSender = new Ping(); // 发送一个Ping请求 var reply = pingSender.Send(ip); if (reply.Status == IPStatus.Success) { listBox1.Invoke(new Action(() => { int index = listBox1.Items.IndexOf(ip); listBox1.Items[index] = ip + " " + "在线"; })); } else { listBox1.Invoke(new Action(() => { int index = listBox1.Items.IndexOf(ip); listBox1.Items[index] = ip + " " + "NO"; })); } }); }); task.Start(); Task.WaitAll(); endTime = DateTime.Now; listBox1.Items.Add(endTime.ToString()); listBox1.Items.Add("OK:" + (endTime - startTime).ToString());
好了,因为使用Task异步编程,界面也不再阻塞和卡顿了,不过运行多少时间不能准确得到,改动一下代码,就是将时间输出定位到任务完成:
task.ContinueWith((t) => { endTime = DateTime.Now; listBox1.Items.Add(endTime.ToString()); listBox1.Items.Add("OK:" + (endTime - startTime).ToString()); });
运行时间为1分41秒,界面不卡顿了。
可是运行仍然是逐个IP地址在ping,根本没有并行计算的效果。虽然使用了Parallel.ForEach,可能是由于线程需要等待导致资源开销过大,那么线程没有被有效地利用。
这其实与普通的使用线程来做没有什么区别了。
4、补充
⑴ 检测方法:
string ipAddress = (string)obj; TcpClient client = new TcpClient(); try { client.Connect(ipAddress, 80); //在线 } catch (Exception ex) { //不在线 } finally { client.Close(); }
引用:
using System.Net.Sockets;
⑵ 检测输入的IP地址是否合法:
IPAddress address; if (IPAddress.TryParse(ipAddress, out address)) { // 检查IP地址是否为IPv4地址 if (address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) return true; }else{ return false; }
对于检测计算机在线与否没有好的方法?看那么多的网络小工具,肯定有!
先完成这个效果,后面再进行优化。
到此这篇关于C#实现网络小程序的步骤详解的文章就介绍到这了,更多相关C#网络小程序内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!