这一切的开始要从同事手中的一个医疗项目开始。
早上一到公司,就看到同事跟数据库连接干上了。要处理的问题是判断网络是否连通。因为如果你不去判断的话,系统只会提示说"sa"登录失败,却不告诉你是因为网络的原因,这会让人相当的郁闷。
我们的客户可不喜欢看到这样"不明不白"的错误,于是我们要做的就是帮他"翻译"过来,让他们知道是因为你们的网络不通,先找网管来检查网络,等到不再提示网络问题的时候再给我们打电话。
要知道跑来跑去是很浪费时间的。
到这里我就想到Scan,它其中一个重要的功能就是扫描网络中在线的IP地址(当然这是需要些其他条件的,这里不是我要说的),于是就想到肯定能用C#来实现这个功能。
于是就开始Google了,后来我就找到了下面的东西:
在这里我用到了线程,如果直接处理的话,时间上有点不能接受。
首先我们找到局域网中在线的IP(这里只处理了一个网段的,如果有时间的朋友也可以研究下怎么处理多网段的)
下面就以192.168.0.0至192.168.0.255为例:
var thread1; private void button2_Click(object sender, EventArgs e)
{
for (int iNum = 0; iNum < 255; iNum++)
{ //ScanIP是下面的方法名
thread1 = new Thread(new ParameterizedThreadStart(ScanIP)); //线程传值
thread1.Start(iNum);
}
}
这里很简单就只是一个循环,唯一看起来不一样的就是线程了。
这里把循环的iNum值传到线程里面去做为IP的最后一段组成:192.168.0.1的格式然后下面再用组合的IP判断网络是否连通。
已经很久没碰线程这块儿了,还是回头看的以前在北大青鸟做的摇奖机项目,最终解决线程后一是高兴,高兴解决了问题,二是感觉我还在吃老本。
我知道是我进步得太慢了,我在努力。
又回到代码,不要忘了还需要导入线程的命名空间:
using System.Threading;
下面是循环调用的扫描方法ScanIP方法
public void ScanIP(object iNum)
{
var ip = "192.168.0." + iNum.ToString();
var ping = new System.Net.NetworkInformation.Ping();
var options = new System.Net.NetworkInformation.PingOptions();
options.DontFragment = true;
string data = "aa";
byte[] buffer = Encoding.ASCII.GetBytes(data); //Wait seconds for a reply.
int timeout = 1000;
System.Net.NetworkInformation.PingReply reply = ping.Send("192.168.0." + iNum, timeout, buffer, options);
SetLblText("正在扫描:" + ip + " - " + reply.Status.ToString(), label3); //Status返回两个状态,Success和TimedOut所以下面也可以写成 //
if (Boolean.Parse(reply.Status.ToString()))
if (reply.Status.ToString().ToUpper() != "TimedOut".ToUpper()) { SetListBoxItem(ip, listView1); } //thread1是在上面按钮事件哪里声明的
thread1.Abort();
}
判断IP是否在线的那段代码我也是直接复制下来用的,都没有改过,囧。。。。。
能实现这样的功能有很多种方法,起码我就找到了两种,觉得这几段看起来更想我想象中的。
大概意思就是执行Cmd命令:ping -n 1 192.168.0.1,然后在返回的结果里面找是不是有"timeout”字样或者你也可以直接在Cmd里面执行:ping -n -1 255.265.65.89看看会返回什么,当然前提是你局域网里面没有这个网段的(要是你有我就,,,我就,,,当我没说-_-!)。
如果没有返回TimedOut那么就表示它在线那么就加入ListView。(在系统中执行Ping你或许看到的是中文,代码应该不是中文,之所以这样判断是因为我并没有得到0到255的所有IP)
如果有那么就表示请求超时了,当然这里也存在一个问题:比如说网络差而造成大量的丢包,或则说硬件错误的时候它不会提示你"timeout",这里点到为止继续说下面的代码。
if里面的那个方法是一个委托,下面是代码:
public delegate void AddOnLineIP(string Value, ListView LBName);
public void SetListBoxItem(string Value, ListView LBName)
{
if (LBName.InvokeRequired)
{
AddOnLineIP OnLineIP = new AddOnLineIP(SetListBoxItem);
LBName.Invoke(OnLineIP, new object[] { Value, LBName });
}
else LBName.Items.Add(new ListViewItem(new string[] { "", Value }));
}
public void SetListBoxItem(string Value, ListView LBName)
{
if (LBName.InvokeRequired)
{
AddOnLineIP OnLineIP = new AddOnLineIP(SetListBoxItem);
LBName.Invoke(OnLineIP, new object[] { Value, LBName });
}
else LBName.Items.Add(new ListViewItem(new string[] { "", Value }));
}
这几句代码我能用,但现在的我还不能具体的解释出来,我的理解就是在线程里面如果要调用控件的话就需要这样用。
囧囧更健康。
下面开始点题了
通过上面的代码我们就把在线的IP给找出来了,但是它的顺序却不是我想要的。于是我也跟它干上了。最后找到下面段看不大明白的代码:
private static uint ConvertToUInt(string ip1)
{
string[] sip = ip1.Split('.');
return (uint.Parse(sip[0]) << 24) | (uint.Parse(sip[1]) << 16) | (uint.Parse(sip[2]) << 8) | (uint.Parse(sip[3]));
}
主要就是<<没看懂,不知道是什么意思,知道的朋友可以说下,先谢了。
这只是个通用方法,要让IP地址排序是这样调用的:
private void listView1_ColumnClick(object sender, ColumnClickEventArgs e)
{
var IPS = new string[listView1.Items.Count];
for (int i = 0; i < listView1.Items.Count; i++)
{
IPS[i] = listView1.Items[i].SubItems[1].Text;
}
listView1.Items.Clear(); //将IPS里面的顺序从组
Array.Sort<string>(IPS, new Comparison<string>(delegate (string ip1, string ip2)
{
return Comparer<uint>.Default.Compare(ConvertToUInt(ip1), ConvertToUInt(ip2));
}));
for (int i = 0; i < IPS.Length; i++)
{
listView1.Items.Add(new ListViewItem(new string[] { "", IPS[i].ToString() }));
}
}
先声明了一个IPS数组长度为ListView1的长度,然后循环ListView1取出来放到数组里面在将这个数组放到ConvertToUInt里面去排序,调用排序的就是中间句Array.Sort那句调用上面的ConvertToUInt方法来实现排序。
最后完了先把ListView1的Item项清空,然后再把刚才排序后的IPS数组给加到ListView1里面就成功了。
差不多了,基本上就是这样了。
在这里留个标记下次的时候就不用去翻以前的项目了,这篇Blog后我对线程又加深印象了。
对于那些现在不懂的,以后再来回顾它。