單線程IP地址解析
目標程序
- 界面如下圖
- 設計方法:完成單個IP地址解析,循環調用方法,完成掃描。
- 注意用stopwatch計算時間。
實現思路
- 先知道怎麼解析一個單個的IP地址。
- 用循環的方法解析多個IP地址。
- 設計程序的界面
- 設計事件
實現過程
在控制檯中嘗試過程
//實現的思路
//掃描的地址是自己設定的,我們需要設置變量來保存它們。
//掃描的IP地址由兩端組成,一個地址前綴,另外一部分時起始值和終止值
//我們需要輸出的是IP地址,掃描時間,和dns主機名
//IP地址可以由IPAddress.Parse轉換
//可以通過Dns.GetHostEntry來解析
//掃描時間可以用stopwatch來統計
//還需要判斷IP地址是否合法
string addressPrefix = "127.0.0.";//用來存儲地址前綴
int startingValue = 1;//存放起始值
int stopingValue = 2;//存放終止值
// if (startingValue <= stopingValue && startingValue > 0 && startingValue <= 255 && stopingValue > 0 && stopingValue <= 255)
//{不用if判斷即可
//用循環來掃描多個IP地址
for (int i = startingValue; i <= stopingValue; i++)
{
string ipString = addressPrefix + i;
IPAddress ip;//不能直接定義在try裏面,不然出了try就不能用了
IPHostEntry iPHostEntry;
string iphostname;
try//判斷是否合法
{
// IPAddress ip = IPAddress.Parse(ipString);
ip = IPAddress.Parse(ipString);
//Dns解析
// IPHostEntry iPHostEntry = Dns.GetHostEntry(ip);
// string iphostname = iPHostEntry.HostName;//獲取ip的主機名
// Console.WriteLine($"掃描地址:{ip},掃描用時,主機DNS名稱:{iphostname}");
//不能大篇幅的try
//要精確點
}
catch (Exception ex)
{
Console.WriteLine("IP地址不合法");
break;
}
Stopwatch sw = new Stopwatch();//實例化一個秒錶對象sw
sw.Start();//秒錶開始
try
{ //Dns解析
iPHostEntry = Dns.GetHostEntry(ip);
iphostname = iPHostEntry.HostName;//獲取ip的主機名
sw.Stop();//秒錶結束
}
catch (Exception ex)
{
iphostname = "不在線";
}
long time = sw.ElapsedMilliseconds;//獲取這段過程的時間
Console.WriteLine($"掃描地址:{ip},掃描用時:{time}毫秒,主機DNS名稱:{iphostname}");
}
//string ipString = addressPrefix + startingValue;//拼接成IP地址字符串
Console.ReadLine();
}
/* else
{
Console.WriteLine("IP地址不合法");
Console.ReadLine();
}*//
設計WPF界面
<Window x:Class="WpfApp_SingleThreadIPScan.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp_SingleThreadIPScan"
mc:Ignorable="d"
Title="單線程IP掃描" Height="450" Width="800"
WindowStartupLocation="CenterScreen">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<GroupBox Grid.Row="0" Header="掃描的IP地址範圍" VerticalContentAlignment="Center" Padding="10">
<DockPanel>
<Label DockPanel.Dock="Left" Content="地址前綴:"/>
<TextBox Name="txt1" Text="192.168.1."/>
<Label Content="起始值:" Margin="15 0 0 0"/>
<TextBox Name="txtStart" Text="102" Margin="0,4,0,0" VerticalAlignment="Top"/>
<Label Content="終止值:" Margin="15 0 0 0"/>
<TextBox Name="txtEnd" Text="105"/>
<Button Name="btn1" Width="60" VerticalAlignment="Center" Content="開始掃描" Click="Button_Click"/>
</DockPanel>
</GroupBox>
<Label Name="labelError" Grid.Row="1" Background="Red" Foreground="White"
Content="IP地址有錯,請更正!" HorizontalContentAlignment="Center" />
<GroupBox Grid.Row="2" Header="掃描信息">
<ListBox x:Name="listBoxInfo"/>
</GroupBox>
</Grid>
</Window>
後臺代碼
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApp_SingleThreadIPScan
{
/// <summary>
/// MainWindow.xaml 的交互邏輯
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
labelError.Visibility = Visibility.Collapsed;//剛開始的時候隱藏報錯的標籤
}
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
string strip1 = txt1.Text + txtStart.Text;
string strip2 = txt1.Text + txtEnd.Text;
IPAddress ip1, ip2;
if (IPAddress.TryParse(strip1, out ip1) == false || IPAddress.TryParse(strip2, out ip2) == false)
{
btn1.IsEnabled = false;
labelError.Visibility = Visibility.Visible;
return;
}
else
{
btn1.IsEnabled = true;
labelError.Visibility = Visibility.Collapsed;
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
int startvalue = int.Parse(txtStart.Text);
int stopvalue = int.Parse(txtEnd.Text);
if (startvalue > stopvalue)
{
MessageBox.Show("起始值必需大於終止值,地址範圍有誤。請改正!");
}
listBoxInfo.Items.Clear();
string ip = "";
for (int i = startvalue; i <= stopvalue; i++)
{
ip = txt1.Text + i;
Scan(ip);
}
}
private void Scan(string ip)
{
string hostname;
Stopwatch sw = Stopwatch.StartNew();
try
{
hostname = Dns.GetHostEntry(ip).HostName;
}
catch(Exception ex)
{
hostname = "(不在線)";
}
sw.Stop();
long time = sw.ElapsedMilliseconds;
listBoxInfo.Items.Add($"掃描地址:{ip},掃描用時:{time}毫秒,DNS主機名:{hostname}");
}
} }
所需要的知識
IP地址
一個IP地址由兩部分組成:
- 網絡號:識別該地址所屬的網絡,它由Internet權力機構分配。
- 主機號:指明網絡內的主機,它由各個網絡的管理員統一分配。
編址方案:
- IPv4編址方案
- 由4個字節(十進制表示)組成的二進制值進行識別,中間用圓點分開,這種方法叫做點分十進制表示法。
- IPv6編址方案
- 每個IP地址有16個字節(128位二進制數),其完整格式用8段16進製表示,各段之間用冒號分隔。
子網掩碼
子網掩碼用於屏蔽IP地址的一部分以區別網絡標識和主機標識。子網掩碼把所有的網絡位(二進制)用1來標識,主機位用0來標識。
- 例如:如果將子網掩碼設置爲255.255.255.0,則對於IP地址192.168.1.X,其網絡標示部分爲192.168.1;主機標示爲:X
可以利用子網掩碼判斷兩臺計算機是否在同一子網內.
- 將其IP地址和子網掩碼做按位與運算,如果得到結果相同即在同一個子網內。
端口
- 物理上的端口。如ADSL Modem、集線器的接口。
- 邏輯意義上的端口,即進程標識
- 端口號的範圍從0到65535
- 1000以內的端口號大多被標準協議所佔用,所以應用程序中可以自由使用的端口號一般都使用大於1000的值。如寶塔面板的8888端口。
C#中關於IP地址轉換的類
- 提供網際協議IP地址的IPAddress類;
- 包含IP地址和端口號的IPEndPoint類;
- 爲Internet或Intranet主機提供信息容器的IPHostEntry類。
IPAddress類
- 位於System.Net命名空間
- 提供了對IP地址的轉換和處理功能
Parse方法:將IP地址字符串轉換爲IPAddress的實例。
IPAddress ipa = IPAddress.Parse(ip);//把IP字符串轉換爲IPaddress類型
但如果該字符串不是IP地址類型,會出現異常。所以我們需要進行異常處理。
System.FormatException:“指定了無效的 IP 地址。”
所以一般我們這樣用:
string ip = "127.0.0.1";//定義一個IP字符串
//IPAddress ipa = IPAddress.Parse(ip);//把IP字符串轉換爲IPaddress類型
try
{
IPAddress ipa = IPAddress.Parse(ip);
}
catch
{
Console.WriteLine("請輸入正確的IP地址!");
Console.ReadLine();
}
AddressFamily屬性
//AddressFamily
IPAddress ip = IPAddress.Parse("::1");
IPAddress ip1 = IPAddress.Parse("127.0.0.1");
if (ip.AddressFamily == AddressFamily.InterNetworkV6)
{
Console.WriteLine("該IP地址採用IPV6編址");
Console.ReadLine();
}
IPAddress類還提供了7個只讀字段,分別代表程序中使用的特殊IP地址。
常見只讀字段
名 稱 | 說 明 |
---|---|
Any | 提供一個IPv4地址,指示服務端應偵聽所有網絡接口上的客戶端活動,它等效於0.0.0.0 |
Broadcast | 提供IPv4網絡廣播地址,它等效於255.255.255.255 |
IPv6Any | 提供所有可用的IPv6地址 |
IPv6Loopback | 表示系統的IPv6迴環地址,等效於::1 |
Loopback | 表示系統的IPv4迴環地址,等效於127.0.0.1 |
IPEndPoint類
- 應用程序連接到主機上的服務所需的主機和端口信息。
- 常用構造函數
IPAddress localAdress = IPAddress.Parse("127.7.0.1");
IPEndPoint iep = new IPEndPoint(localAdress, 21);//初始化IPEndPoint類
string ipaddress = "IP地址爲"+iep.Address;//此處利用拼接字符串把IPAddress轉換爲字符串型
string port = "端口號爲" + iep.Port;
Console.WriteLine($"{ipaddress}\n{port}");
Console.ReadLine();
IPHostEntry類
將一個域名系統(DNS)的主機名與一組別名和一組匹配的IP地址關聯。該類一般和Dns類一起使用。
域名解析
爲什麼引入域名系統?
- 網絡主機使用IP地址來定位
- IP難於記憶,需要用名稱來表示主機
- IP地址改變後,域名不變,仍可訪問
.NET框架在System.Net命名空間提供了Dns類完成解析
方法名稱 | 說 明 |
---|---|
GetHostAddresses | 返回指定主機的Internet協議IP地址與該方法對應的還有異步方法 |
GetHostEntry | 將主機名或IP地址解析爲IPHostEntry實例該方法對應的還有異步方法 |
GetHostName | 獲取本地計算機的主機名 |
GetHostAddresses方法
指定主機的IP地址,返回一個IPAddress類型的數組。
- public static IPAddress[] GetHostAddresses(string hostNameOrAddress);
- 參數中的hostNameOrAddress表示要解析的主機名或IP地址。
- 若hostNameOrAddress是IP地址,則直接返回此地址;若是空字符串,則返回本機所有IPv4和IPv6地址。
IPAddress[] ips = Dns.GetHostAddresses("baidu.com"); //定義一個數組來存放從主機來解析的IPAddress類
IPAddress[] ips1 = Dns.GetHostAddresses("www.cctv.com");
IPAddress[] ips2 = Dns.GetHostAddresses("127.0.0.1");//若hostNameOrAddress是IP地址,則直接返回此地址;
IPAddress[] ips3 = Dns.GetHostAddresses("");//若是空字符串,則返回本機所有IPv4和IPv6地址。
foreach (var i in ips3)
{
Console.WriteLine(i);
}
Console.ReadLine()
GetHostEntry方法
根據主機名或IP地址返回一個IPHostEntry實例,用於在DNS服務器中查詢與某個主機名或IP地址關聯的IP地址列表。
- public static IPHostEntry GetHostEntry (string hostNameOrAddress)
- hostNameOrAddress表示要解析的主機名或IP地址
- 當參數爲空字符串時,返回本地主機的IPHostEntry實例。
IPHostEntry iPHostEntry = Dns.GetHostEntry("");
var iplist = iPHostEntry.AddressList;//獲取IP地址列表
var hostname = iPHostEntry.HostName;//獲取主機名
foreach(var i in iplist)
{
Console.WriteLine(i);
}
Console.WriteLine($"主機名字爲{hostname}");
Console.ReadLine();
GetHostName方法
該方法用於獲取本機主機名。
string hostname = Dns.GetHostName();
Console.WriteLine($"本機的主機名爲:{hostname}");
Console.ReadLine();