题目描述:

    创建一个WPF应用程式,用多任务扫描一个网段内的计算机,根据计算机的IP地址获取其主机域名。

XAML文件描述:

    我用的是一个Canvers里面嵌套Grid,然后Grid分三行(分别是2*,1*,3*)。第一行里面放label和TextBox用于提示并且获取用户输入的网段。第二行errorLabel错误提示,我用的算法是错误时Visible,输入正确时Hidden。第三行里面放一个GroupBox,然后里面放一个ListBox,margin="3".

关于美工和界面设计我基本不会,属于完全的门外汉。虽说大二了,可是对photoshop还有设计学一无所知。每次的界面设计对我真的是煎熬(此刻难受五秒钟......)。

XAML文件代码实现:

     <Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Canvas>
    <GroupBox Header="扫描的IP地址:" Height="313" Width="507">
        <Grid Height="293" VerticalAlignment="Top">
            <Grid.RowDefinitions>
                <RowDefinition Height="2*"/>
                <RowDefinition Height="1*"/>
                <RowDefinition Height="3*"/>
            </Grid.RowDefinitions>
            <Label Content="地址前缀:" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Height="24" Width="70"/>
            <TextBox x:Name="qianzhui" HorizontalAlignment="Left" Height="23" Margin="80,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="78"/>
            <Label Content="起始值:" HorizontalAlignment="Left" Margin="163,10,0,0" VerticalAlignment="Top" Height="24" Width="58"/>
            <TextBox x:Name="qishi" HorizontalAlignment="Left" Height="23" Margin="221,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="90"/>
            <Label Content="终止值:" HorizontalAlignment="Left" Margin="316,10,0,0" VerticalAlignment="Top"/>
            <TextBox x:Name="zhongzhi" HorizontalAlignment="Left" Height="23" Margin="382,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="103"/>
            <Label x:Name="errorLable" Background="Red" Foreground="White" FontSize="19" Content="IP地址有错,请更正!" HorizontalAlignment="Center" Margin="10,10,0,0" Grid.Row="1" VerticalAlignment="Center" Width="475" Height="36" HorizontalContentAlignment="Center"/>
            <GroupBox Header="扫描信息:" HorizontalAlignment="Left" Margin="10,10,0,0" Grid.Row="2" VerticalAlignment="Top" RenderTransformOrigin="0.212,-1.15" Height="126" Width="475">
                <ListBox x:Name="listBox" HorizontalAlignment="Left" Height="100" Margin="3" VerticalAlignment="Top" Width="444"/>
            </GroupBox>
            <Button  Content="开始扫描" HorizontalAlignment="Left" Margin="163,55,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
        </Grid>
    </GroupBox>
</Canvas>

咳咳,属性设置的很啰嗦并且不自然,我是不会告诉你我是用拖放的。其实老师课上讲过一次:“基本控件最好不要用拖放,因为那样是绝对的布局,使得软体的可移植性差”。可是啊,感觉总是找不到好的解决办法。

.CS文件代码实现:

using System;
using System.Collections.Generic;
using System.Linq;
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;
using System.Net;
using System.Threading;
namespace WpfApplication1
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{   int n = 0;
    public MainWindow()
    {

        DateTime taskBegin = DateTime.Now;
        InitializeComponent();
        qianzhui.Text = "192.168.1.";
        qishi.Text = "102";
        zhongzhi.Text = "105";
    }
    private void textBox_TextChanged(object sender, TextChangedEventArgs e)
    {
        IPAddress ipstart;
        IPAddress ipend;
        if (IPAddress.TryParse(qianzhui.Text + qishi.Text, out ipstart) && IPAddress.TryParse(qianzhui.Text + zhongzhi.Text, out ipend))
        {
            errorLable.Visibility = Visibility.Hidden;
        }
        else
        {
            errorLable.Visibility = Visibility.Visible;
        }
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        IPAddress ipstart;
        IPAddress ipend;
        listBox.Items.Clear();
        n= int.Parse(zhongzhi.Text) - int.Parse(qishi.Text) + 1;
        if (IPAddress.TryParse(qianzhui.Text + qishi.Text, out ipstart) && IPAddress.TryParse(qianzhui.Text + zhongzhi.Text, out ipend))
        {
            errorLable.Visibility = Visibility.Hidden;
            for (int i = int.Parse(qishi.Text); i <= int.Parse(zhongzhi.Text); i++)
            {
                IPAddress ip = IPAddress.Parse(qishi.Text + i.ToString());
                Thread t = new Thread(scan);
                t.Start(ip);
            }
        }
        else
        {
            errorLable.Visibility = Visibility.Visible;
        }
    }
    private void scan(Object ip)
    {
        DateTime taskBegin = DateTime.Now;
        DateTime begin = DateTime.Now;
        IPAddress ipAddress = (IPAddress)ip;
        string hostName;
        try
        {
            hostName = Dns.GetHostEntry(ipAddress).HostName;
        }
        catch
        {
            hostName = "(不在线)";
        }
        DateTime end = DateTime.Now;
        TimeSpan ts = end - begin;
        listBox.Dispatcher.Invoke(() => listBox.Items.Add("扫描地址:" + ipAddress.ToString() + " 扫描用时:" + ts.TotalMilliseconds + "毫秒 " + " 主机名称:" + hostName));
        n--;
        if (n == 0)
        {
            DateTime taskEnd = DateTime.Now;
            TimeSpan taskAll = taskEnd - taskBegin;
            MessageBox.Show("扫描完毕!总用时:" + taskAll.TotalMilliseconds + "毫秒");
        }
    }
}
}

.CS代码的注意点:

1.因为要根据IP地址查询对应的主机名称,所以会用到.NET命名空间中的Dns类的域名解析功能,可以查询到每个IP对应的DNS名。但是GetHostEntry方法有个参数,也就是合法的IP这时就需要IPAddress类里的静态Parse方法,它可以将IP地址的字符串转化为IPAddress的实例。 

2.因为是多任务异步执行 ,会用到多线程,老师讲过多个线程争夺相同的一个代码段会出现死锁的情况。为了避免,可以利用WPF控件的Dispatcher属性,它会自动在线程池里按照优先级对工作项进行调度。这里我用的是Invoke来注册(同步调用),好像是通过执行特定的委托来实现的,具体忘了==。

3.还有就是执行时间的问题了,不知道这样写有没有问题。

鼓励自己:

并不是自己记性不好,而是没有掌握,如果真的理解就不会忘。而从闻所未闻到如鱼得水,需要重复,希望自己能多点耐心,不要太过于急功近利。还有,明明是那女孩追我,反而自己搞得比人家还不自然,真是的,定力不够。哦,对了,可以抽空去图书馆啃啃高纳德前辈的《Java编程思想》,别忘了带上笔记本。