網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
經(jīng)常要檢測(cè)某些IP地址范圍段的計(jì)算機(jī)是否在線。
有很多的方法,比如進(jìn)入到網(wǎng)關(guān)的交換機(jī)上去查詢、使用現(xiàn)成的工具或者編寫一個(gè)簡(jiǎn)單的DOS腳本等等,這些都比較容易實(shí)現(xiàn)。
現(xiàn)在使用C#來(lái)完成。
1、簡(jiǎn)單上手
公用函數(shù):
public static long IPToLong(string ip)
{
//將IP地址轉(zhuǎn)換為長(zhǎng)整數(shù)
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)
{
//將長(zhǎng)整數(shù)IP地址轉(zhuǎn)換為實(shí)際的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;
}
點(diǎn)擊【檢測(cè)】按鈕:
DateTime startTime, endTime;
startTime= DateTime.Now;
listBox1.Items.Add(startTime.ToString());
string startIP = textBox1.Text;
string endIP = textBox2.Text;
// 將起始IP地址和結(jié)束IP地址轉(zhuǎn)換為長(zhǎng)整數(shù)
long startIPLong = IPToLong(startIP);
long endIPLong = IPToLong(endIP);
Ping ping = new Ping();
// 遍歷IP地址范圍
for (long i = startIPLong; i <= endIPLong; i++)
{
// 將整數(shù)轉(zhuǎn)換為IP地址
string ip = LongToIP(i);
// 輸出
PingReply pingReply = ping.Send(ip);
if (pingReply.Status == IPStatus.Success)
{
listBox1.Items.Add( ip + "=>計(jì)算機(jī)在線");
}
else
{
listBox1.Items.Add(ip);
}
}
endTime = DateTime.Now;
listBox1.Items.Add(endTime.ToString());
listBox1.Items.Add("OK:" + (endTime - startTime).ToString());
執(zhí)行時(shí)沒(méi)有問(wèn)題的,可以出來(lái)結(jié)果,問(wèn)題是界面卡頓了。
執(zhí)行的時(shí)間也很長(zhǎng),執(zhí)行需要1分21秒。
這個(gè)結(jié)果不能接受,需要對(duì)程序加以改進(jìn)。
2、使用并行計(jì)算
不需要改動(dòng)公用代碼,只需要改動(dòng)檢測(cè)部分。
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地址和結(jié)束IP地址轉(zhuǎn)換為整數(shù)
long startIPLong = IPToLong(startIP);
long endIPLong = IPToLong(endIP);
// 創(chuàng)建一個(gè)可以存儲(chǔ)IP地址的List
List<string> ipList = new List<string>();
for (long i = startIPLong; i <= endIPLong; i++)
{
// 將整數(shù)轉(zhuǎn)換為IP地址
string ip = LongToIP(i);
ipList.Add(ip);
ipResults.Add(ip,"");
listBox1.Items.Add(ip);
}
// 開啟并行計(jì)算
Parallel.ForEach(ipList, (ip) =>
{
// 創(chuàng)建一個(gè)新的Ping類
Ping pingSender = new Ping();
// 發(fā)送一個(gè)Ping請(qǐng)求
var reply = pingSender.Send(ip);
// 如果返回的狀態(tài)是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());
增加一個(gè)公用函數(shù):
public void ChangeIPStatus(string ip,string S1)
{
// 定位到listbox中記錄并更改IP是否在線
int index = listBox1.Items.IndexOf(ip);
listBox1.Items[index] = ip+" "+S1;
}
出現(xiàn)問(wèn)題:
⑴ 提示“C#線程間操作無(wú)效:從不是創(chuàng)建控件“textbox1”的線程訪問(wèn)它”,這個(gè)就簡(jiǎn)單設(shè)置Control.CheckForIllegalCrossThreadCalls=false即可解決;
⑵ 提示“l(fā)istbox1包含的項(xiàng)太多”,這個(gè)是不是與并行計(jì)算開啟的線程太多有關(guān)?考慮到本機(jī)是8核,保守一點(diǎn),修改參數(shù)
Parallel.ForEach(ipList, new ParallelOptions() { MaxDegreeOfParallelism = MaxDegreeOfParallelism = Environment.ProcessorCount }, (ip) =>
{
//執(zhí)行代碼
}
程序可以正常運(yùn)行了。
⑶ 界面依然阻塞,但用時(shí)更多了。
去ping255個(gè)地址,竟然用了12分32秒!!!這個(gè)真是不可忍受,最關(guān)鍵沒(méi)有界面交互,這太不用戶友好了!
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地址和結(jié)束IP地址轉(zhuǎn)換為整數(shù)
long startIPLong = IPToLong(startIP);
long endIPLong = IPToLong(endIP);
// 創(chuàng)建一個(gè)可以存儲(chǔ)IP地址的List
List<string> ipList = new List<string>();
for (long i = startIPLong; i <= endIPLong; i++)
{
// 將整數(shù)轉(zhuǎn)換為IP地址
string ip = LongToIP(i);
ipList.Add(ip);
ipResults.Add(ip,"");
listBox1.Items.Add(ip);
}
Task task = new Task(() =>
{
// 創(chuàng)建一個(gè)多線程
Parallel.ForEach(ipList, new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount }, (ip) =>
{
// 創(chuàng)建一個(gè)新的Ping類
Ping pingSender = new Ping();
// 發(fā)送一個(gè)Ping請(qǐng)求
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());
好了,因?yàn)槭褂肨ask異步編程,界面也不再阻塞和卡頓了,不過(guò)運(yùn)行多少時(shí)間不能準(zhǔn)確得到,改動(dòng)一下代碼,就是將時(shí)間輸出定位到任務(wù)完成:
task.ContinueWith((t) =>
{
endTime = DateTime.Now;
listBox1.Items.Add(endTime.ToString());
listBox1.Items.Add("OK:" + (endTime - startTime).ToString());
});
運(yùn)行時(shí)間為1分41秒,界面不卡頓了。
可是運(yùn)行仍然是逐個(gè)IP地址在ping,根本沒(méi)有并行計(jì)算的效果。雖然使用了Parallel.ForEach,可能是由于線程需要等待導(dǎo)致資源開銷過(guò)大,那么線程沒(méi)有被有效地利用。
這其實(shí)與普通的使用線程來(lái)做沒(méi)有什么區(qū)別了。
4、補(bǔ)充
⑴ 檢測(cè)方法:
string ipAddress = (string)obj;
TcpClient client = new TcpClient();
try
{
client.Connect(ipAddress, 80);
//在線
}
catch (Exception ex)
{
//不在線
}
finally
{
client.Close();
}
引用:
using System.Net.Sockets;
⑵ 檢測(cè)輸入的IP地址是否合法:
IPAddress address;
if (IPAddress.TryParse(ipAddress, out address))
{
// 檢查IP地址是否為IPv4地址
if (address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
return true;
}else{
return false;
}
對(duì)于檢測(cè)計(jì)算機(jī)在線與否沒(méi)有好的方法?看那么多的網(wǎng)絡(luò)小工具,肯定有!
先完成這個(gè)效果,后面再進(jìn)行優(yōu)化。
原文鏈接:https://blog.csdn.net/dawn0718/article/details/128449738
相關(guān)推薦
- 2022-03-31 Python基礎(chǔ)中的列表你了解嗎_python
- 2022-07-07 Python如何使用type()函數(shù)查看數(shù)據(jù)的類型_python
- 2022-10-03 iOS?Objective-c實(shí)現(xiàn)左右滑動(dòng)切換頁(yè)面_IOS
- 2022-04-18 html2canvas 畫圖出現(xiàn)空白的情況,引出圖片跨域的相關(guān)問(wèn)題
- 2022-10-30 SwiftUI?List在MacOS中的性能優(yōu)化示例_Swift
- 2023-01-12 Golang單元測(cè)試與斷言編寫流程詳解_Golang
- 2022-12-04 WxPython界面利用pubsub如何實(shí)現(xiàn)多線程控制_python
- 2021-11-13 Gateway網(wǎng)關(guān)工作原理及使用方法_其它綜合
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支