Как быстрее пинговать при достижении недоступного IP? - PullRequest
8 голосов
/ 19 января 2012

У меня есть приложение, которое пингует IP или диапазон IP.Проблема заключается в том, что когда узлы закрыты, пинг занимает больше времени, чем они открыты.Когда хост закрыт, время пинга составляет около 1-2 секунд.

Как я могу сделать это быстрее, когда хосты закрыты?

Это мой код:

using System;
using System.Text;
using System.Windows.Forms;
using System.Net.NetworkInformation;

namespace Range_Pinger
{
    public partial class PingIPRange : Form
    {
        uint startIP, endIP, currentIP;
        int count = 0;
        int open = 0;
        int closed = 0;

        public PingIPRange()
        {
            InitializeComponent();

            tmrPingInterval.Tick += new EventHandler(tmrPingInterval_Tick);
        }

        void tmrPingInterval_Tick(object sender, EventArgs e)
        {
            if (txtTo.Text == string.Empty) Ping(ip2str(startIP));
            else
            {
                if (currentIP >= endIP) tmrPingInterval.Stop();
                Ping(ip2str(currentIP));
                currentIP++;
            }

            count++;

            tsslPingCount.Text = "Total number of pings: " + count.ToString() + 
                " Open IPs: " + open.ToString() + " Closed IPs: " + closed.ToString();
        }

        static uint str2ip(string ip)
        {
            string[] numbers = ip.Split('.');

            uint x1 = (uint)(Convert.ToByte(numbers[0]) << 24);
            uint x2 = (uint)(Convert.ToByte(numbers[1]) << 16);
            uint x3 = (uint)(Convert.ToByte(numbers[2]) << 8);
            uint x4 = (uint)(Convert.ToByte(numbers[3]));

            return x1 + x2 + x3 + x4;
        }

        static string ip2str(uint ip)
        {
            string s1 = ((ip & 0xff000000) >> 24).ToString() + ".";
            string s2 = ((ip & 0x00ff0000) >> 16).ToString() + ".";
            string s3 = ((ip & 0x0000ff00) >> 8).ToString() + ".";
            string s4 = (ip & 0x000000ff).ToString();

            return s1 + s2 + s3 + s4;
        }


        private void btnPing_Click(object sender, EventArgs e)
        {
            txtDisplay.Text = string.Empty;
            tsslPingCount.Text = string.Empty; 
            count = 0;
            open = 0;
            closed = 0;
            tmrPingInterval.Interval = int.Parse(nudInterval.Value.ToString());

            try
            {
                startIP = str2ip(txtFrom.Text);
                if (txtTo.Text != string.Empty) endIP = str2ip(txtTo.Text);
                currentIP = startIP;
                tmrPingInterval.Start();
            }
            catch
            {
                MessageBox.Show("Invalid input. It must be something like: 255.255.255.255");
            }
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            tmrPingInterval.Stop();
        }

        private void Ping(string address)
        {
            Ping pingSender = new Ping();
            PingOptions options = new PingOptions();
            options.DontFragment = true;
            string data = "01234567890123456789012345678901";
            byte[] buffer = Encoding.ASCII.GetBytes(data);
            int timeout = 120;
            try
            {
                PingReply reply = pingSender.Send(address, timeout, buffer, options) ;
                if (reply.Status == IPStatus.Success)
                {
                    open++;
                    txtDisplay.AppendText("Host " + address + " is open." + Environment.NewLine);
                }
                else
                {
                    closed++;
                    txtDisplay.AppendText("Host " + address + " is closed." + Environment.NewLine);
                }
            }
            catch (Exception ex)
            {
                txtDisplay.SelectedText += Environment.NewLine + ex.Message;
            }
        }

        private void tsmiExit_Click(object sender, EventArgs e)
        {
            this.Close();
        }
    }
}

Вот что у меня сейчас:

    [DllImport("iphlpapi.dll", ExactSpelling = true)]
    public static extern int SendARP(IPAddress DestIP, int SrcIP, byte[] pMacAddr, ref uint PhyAddrLen);

    private void Ping(IPAddress address)
    {
        byte[] macAddr = new byte[6];
        uint macAddrLen = (uint)macAddr.Length;

        if (SendARP(address, 0, macAddr, ref macAddrLen) == 0)
        {
            txtDisplay.AppendText("Host " + address + " is open." + Environment.NewLine);
        }
        else txtDisplay.AppendText("Host " + address + " is closed." + Environment.NewLine);
    }

Ответы [ 5 ]

10 голосов
/ 19 января 2012

Вы не должны сокращать время ожидания.Попробуйте отправить несколько пингов одновременно.

var ping = new Ping();
ping.PingCompleted += (sender, eventArgs) =>
{
    // eventArgs.Reply.Address
    // eventArgs.Reply.Status
};
ping.SendAsync(ip, etc.);
7 голосов
/ 19 января 2012

Ваш адрес string. Таким образом, сначала он пройдет через DNS, чтобы узнать, возможно ли это имя хоста (даже если это IP-адрес).

Я предлагаю вам использовать перегрузку вместо IPAddress.

4 голосов
/ 19 января 2012

Я создал сканер живого хоста не так давно. Он использует ARP, чтобы проверить, подключен ли компьютер к сети. Запрос ARP намного быстрее, чем если бы вы пинговали хост. Вот код, который я использовал для проверки доступности хоста:

//You'll need this pinvoke signature as it is not part of the .Net framework
[DllImport("iphlpapi.dll", ExactSpelling = true)]
public static extern int SendARP(int DestIP, int SrcIP, 
                                 byte[] pMacAddr, ref uint PhyAddrLen);

//These vars are needed, if the the request was a success 
//the MAC address of the host is returned in macAddr
private byte[] macAddr = new byte[6];
private uint macAddrLen;

//Here you can put the IP that should be checked
private IPAddress Destination = IPAddress.Parse("127.0.0.1");

//Send Request and check if the host is there
if (SendARP((int)Destination.Address, 0, macAddr, ref macAddrLen) == 0)
{
    //SUCCESS! Igor it's alive!
}

Если вам интересно Nmap также использует эту технику для поиска доступных хостов.

Сканирование ARP позволяет Nmap и его оптимизированным алгоритмам отвечать за запросы ARP. И если он получает ответ, Nmap даже не нужно беспокоиться о ping-пакетах на основе IP, поскольку он уже знает, что хост работает. Это делает сканирование ARP намного быстрее и надежнее, чем сканирование на основе IP. Таким образом, это делается по умолчанию при сканировании узлов Ethernet, которые обнаруживает Nmap в локальной сети Ethernet. Даже если указаны разные типы ping (например, -PE или -PS), Nmap использует ARP вместо любой цели, находящейся в одной и той же локальной сети.

EDIT:

Это работает только в текущей подсети! Пока между запрашивающей машиной и целью нет маршрутизатора, он должен работать нормально.

ARP - это не маршрутизируемый протокол, и поэтому его можно использовать только между системами в одной сети Ethernet. [...] arp-scan может использоваться для обнаружения IP-хостов в локальной сети. Он может обнаружить все хосты, включая те, которые блокируют весь IP-трафик, такой как брандмауэры и системы с входными фильтрами. - Выдержка из вики NTA-Monitor

Для получения дополнительной информации о функции SendARP вы можете проверить документацию pinvoke.net .

3 голосов
/ 19 января 2012

Вам необходимо изменить дизайн приложения, чтобы использовать многопоточность -> задачи.Выполните задачу для каждого пинга, и когда вы получите ответ от данного хоста, вызовите событие и обновите интерфейс.Изменение времени ожидания сокета поможет вам уменьшить время ожидания от возмутительного до невыносимого.

2 голосов
/ 19 января 2012

Не уверен, если это какая-то помощь (см. Последний пост в теме), кажется, почти идентичная проблема. То, с чем вы сталкиваетесь, это время ожидания стека протоколов. Вы можете обойти это, если будете использовать сокет для подключения, поскольку у вас будет больше контроля.

...