Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Распределённые приложения и сеть > Определить включен ли компьютер в локальной сети


Автор: Turanda 2.11.2010, 11:50
В принципе тема не новая тут, но подходящего не нашел поэтому решил создать тему.

Проблема в том что нужно просканировать локальную сеть по IP и узнать какие включены.

сейчас делаю это так:

Код


localMachineInfo = Dns.GetHostEntry(ip);



Но это работает очень медленно причем, если хост недоступен то проверка его длится еще дольше.

Есть такая программа Xspider сканер безопасности, ну или другие сканеры сетей, вот интерестно как у них организовано сканирование, т.к. упомянутый спайдер сканит за 3 секунды весь диапазон. 

Как такого же добиться?

Автор: gambit 2.11.2010, 12:06
Turanda, возможно вариант безумный, я не спец в сетях, но он пришел в голову первым.
Пинг.
Ответили - работаем, не ответили за секунду, значит выключен. Массового разослать пинг по сети, прослушать ответы, сделать вывод кто включен, а кто нет

Автор: Turanda 2.11.2010, 12:32
вот получалось теперь так:
Код

int time=100;
for ( i = 1; i < 21; i++)
            {
                ip = "192.168.1." + i.ToString();
                System.Net.NetworkInformation.Ping p = new System.Net.NetworkInformation.Ping();
                System.Net.NetworkInformation.PingReply reply = p.Send(ip,time);
                if (reply.Status == System.Net.NetworkInformation.IPStatus.Success)
                {
                    richTextBox1.Text = richTextBox1.Text+"  "+ ip + "\n";
                }
            }


Да добавил время стало намного быстрей, можно сказать наверное даже что проблема решена smile

Автор: mihryak 2.11.2010, 13:43
сейчас меня gambit заклюёт, но советую взглянуть на интеропные функции - и возможностей больше, и скорость куда выше
ещё такая таска отлично параллелится, можно создать кучу потоков для проверки компов
ну и я тут попробовал идти не от адресов, а от имеющих компов - это избавит от проверок заведомо недоступных машин, т.е. получаю список компов, а там уже можно проверить его адреса на вхождение в диапазон
такой код в приличном домене отрабатывает за 99мс:
Код

    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            foreach(string computerName in GetComputers(Environment.UserDomainName))
            {
                Console.WriteLine("Computer: {0}. IP: {1}.",
                    computerName, string.Join(", ",
                    Dns.GetHostAddresses(computerName).Select(a => a.ToString()).ToArray()));
            }
            stopwatch.Stop();
            Console.WriteLine("Elapsed time: {0}.", stopwatch.ElapsedMilliseconds);
            Console.ReadKey();
        }

        static List<string> GetComputers(string domain)
        {
            NETRESOURCE nr = new NETRESOURCE();
            nr.dwScope = RESOURCE_SCOPE.RESOURCE_GLOBALNET;
            nr.dwType = RESOURCE_TYPE.RESOURCETYPE_ANY;
            nr.dwUsage = RESOURCE_USAGE.RESOURCEUSAGE_CONTAINER;
            nr.dwDisplayType = RESOURCE_DISPLAYTYPE.DOMAIN;
            nr.lpProvider = GetMSWindowsNetworkName();
            nr.lpRemoteName = domain;

            return GetNetworkItems(nr, new List<RESOURCE_DISPLAYTYPE>
                                           {
                                               RESOURCE_DISPLAYTYPE.SERVER
                                           });
        }

        static string GetMSWindowsNetworkName()
        {
            StringBuilder builder = new StringBuilder(0);
            int size = 0;
            const int WNNC_NET_LANMAN = 0x00020000;
            ErrorCode errorCode = WNetGetProviderName(WNNC_NET_LANMAN, builder, ref size);
            if (errorCode == ErrorCode.MoreData)
            {
                builder.EnsureCapacity(size);
                WNetGetProviderName(WNNC_NET_LANMAN, builder, ref size);
            }

            return builder.ToString();
        }

        static List<string> GetNetworkItems(NETRESOURCE parentResource,
            IEnumerable<RESOURCE_DISPLAYTYPE> searchTypes)
        {
            var items = new List<string>();

            IntPtr ptrBuffer = IntPtr.Zero;
            IntPtr ptrHandle = new IntPtr();

            try
            {
                int iRet = WNetOpenEnum(RESOURCE_SCOPE.RESOURCE_GLOBALNET, RESOURCE_TYPE.RESOURCETYPE_ANY,
                    RESOURCE_USAGE.RESOURCEUSAGE_ALL, parentResource, out ptrHandle);

                if (iRet == 0)
                {
                    int bufferSize = 16384;
                    ptrBuffer = Marshal.AllocHGlobal(bufferSize);

                    while (true)
                    {
                        int entries = -1;
                        iRet = WNetEnumResource(ptrHandle, ref entries, ptrBuffer, ref bufferSize);

                        if ((iRet != 0) || (entries < 1))
                        {
                            break;
                        }
                        int ptr = ptrBuffer.ToInt32();
                        for (int i = 0; i < entries; i++)
                        {
                            NETRESOURCE resource = (NETRESOURCE)Marshal.PtrToStructure(
                                new IntPtr(ptr), typeof(NETRESOURCE));
                            ptr += Marshal.SizeOf(resource);
                            if (searchTypes.Contains(resource.dwDisplayType))
                            {
                                items.Add(resource.lpRemoteName.Trim('\\'));
                            }
                        }
                    }
                }
            }
            finally
            {
                Marshal.FreeHGlobal(ptrBuffer);
                WNetCloseEnum(ptrHandle);
            }

            return items;
        }

        enum RESOURCE_TYPE
        {
            RESOURCETYPE_ANY = 0x00000000,
            RESOURCETYPE_DISK = 0x00000001,
            RESOURCETYPE_PRINT = 0x00000002,
            RESOURCETYPE_RESERVED = 0x00000008,
        }

        enum RESOURCE_USAGE
        {
            RESOURCEUSAGE_CONNECTABLE = 0x00000001,
            RESOURCEUSAGE_CONTAINER = 0x00000002,
            RESOURCEUSAGE_NOLOCALDEVICE = 0x00000004,
            RESOURCEUSAGE_SIBLING = 0x00000008,
            RESOURCEUSAGE_ATTACHED = 0x00000010,
            RESOURCEUSAGE_ALL = (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_ATTACHED),
        }

        struct NETRESOURCE
        {
            public RESOURCE_SCOPE dwScope;
            public RESOURCE_TYPE dwType;
            public RESOURCE_DISPLAYTYPE dwDisplayType;
            public RESOURCE_USAGE dwUsage;
            [MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPTStr)]
            public string lpLocalName;
            [MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPTStr)]
            public string lpRemoteName;
            [MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPTStr)]
            public string lpComment;
            [MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPTStr)]
            public string lpProvider;
        }

        enum RESOURCE_DISPLAYTYPE
        {
            GENERIC = 0x00000000,
            DOMAIN = 0x00000001,
            SERVER = 0x00000002,
            SHARE = 0x00000003,
            FILE = 0x00000004,
            GROUP = 0x00000005,
            NETWORK = 0x00000006,
            ROOT = 0x00000007,
            SHAREADMIN = 0x00000008,
            DIRECTORY = 0x00000009,
            TREE = 0x0000000A,
            NDSCONTAINER = 0x0000000B
        }

        enum RESOURCE_SCOPE
        {
            RESOURCE_CONNECTED = 0x00000001,
            RESOURCE_GLOBALNET = 0x00000002,
            RESOURCE_REMEMBERED = 0x00000003,
            RESOURCE_RECENT = 0x00000004,
            RESOURCE_CONTEXT = 0x00000005
        }

        enum ErrorCode
        {
            Success = 0,
            MoreData = 234
        }

        [DllImport("mpr.dll", CharSet = CharSet.Auto)]
        static extern ErrorCode WNetGetProviderName(int networkType,
            [Out] StringBuilder builder, ref int buffersSize);

        [DllImport("mpr.dll", CharSet = CharSet.Auto)]
        static extern int WNetEnumResource(IntPtr hEnum, ref int lpcCount,
            IntPtr lpBuffer, ref int lpBufferSize);

        [DllImport("mpr.dll", CharSet = CharSet.Auto)]
        static extern int WNetOpenEnum(RESOURCE_SCOPE dwScope, RESOURCE_TYPE dwType,
            RESOURCE_USAGE dwUsage, [MarshalAs(UnmanagedType.AsAny)] [In] Object lpNetResource, out IntPtr lphEnum);

        [DllImport("mpr.dll", CharSet = CharSet.Auto)]
        static extern int WNetCloseEnum(IntPtr hEnum);
    }

Автор: gambit 2.11.2010, 15:25
Цитата(mihryak @  2.11.2010,  13:43 Найти цитируемый пост)
сейчас меня gambit заклюёт

С чего?
Даже профессионалы могут ошибаться, не говоря уже про меня.
Тем более я написал:
Цитата(gambit @  2.11.2010,  12:06 Найти цитируемый пост)
  вариант безумный, я не спец в сетях, но он пришел в голову первым. 


Добавлено через 45 секунд
Цитата(mihryak @  2.11.2010,  13:43 Найти цитируемый пост)
ейчас меня gambit заклюёт

хотя
Код

[DllImport("mpr.dll", CharSet = CharSet.Auto)]

не айс

Добавлено через 3 минуты и 36 секунд
А если отталкиваться от моей безумной идеи, и распараллелить вот это
Цитата(Turanda @  2.11.2010,  12:32 Найти цитируемый пост)
int time=100;
for ( i = 1; i < 21; i++)
            {
                ip = "192.168.1." + i.ToString();
                System.Net.NetworkInformation.Ping p = new System.Net.NetworkInformation.Ping();
                System.Net.NetworkInformation.PingReply reply = p.Send(ip,time);
                if (reply.Status == System.Net.NetworkInformation.IPStatus.Success)
                {
                    richTextBox1.Text = richTextBox1.Text+"  "+ ip + "\n";
                }
            }

получиться конфетка. Правда стоит учесть, что вкл. комп тоже может не ответить на пинг

Добавлено через 11 минут и 59 секунд
Код

int time = 100;
            ConcurrentBag<string> mas = new ConcurrentBag<string>();

            Parallel.For(0, 21, i =>
                {
                    string ip = "192.168.1." + i.ToString();
                    System.Net.NetworkInformation.Ping p = new System.Net.NetworkInformation.Ping();
                    System.Net.NetworkInformation.PingReply reply = p.Send(ip, time);
                    if (reply.Status == System.Net.NetworkInformation.IPStatus.Success)
                    {
                        mas.Add(ip);
                    }
                });

Автор: mihryak 2.11.2010, 17:15
Цитата(gambit @  2.11.2010,  16:25 Найти цитируемый пост)

С чего?

да как-то уже накинулся на меня со словами, что интероп - это не тру в шарпе

Цитата(gambit @  2.11.2010,  16:25 Найти цитируемый пост)
[DllImport("mpr.dll", CharSet = CharSet.Auto)]
не айс

с чего? smile

Автор: gambit 2.11.2010, 17:23
mihryak, 
Цитата(mihryak @  2.11.2010,  17:15 Найти цитируемый пост)
да как-то уже накинулся на меня со словами, что интероп - это не тру в шарпе

если имеется ввиду вот эта тема - http://forum.vingrad.ru/forum/topic-306772/kw-%D0%BE%D0%B1%D0%BD%D0%BE%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80/view-all.html
ну не сказать что я накинулся, просто высказал мнение о том, что без этого можно обойтись.
Не знаю, может это моя личная неприязнь, но я буду как уж выворачиваться, но на интеропные функции не посмотрю.

Автор: mihryak 2.11.2010, 18:58
Ну вот на более серьёзном диапазоне (192.168.0.0-192.168.255.255) у меня компы проверились за 3.5 секунды, а твой вариант (без распараллеливания, правда, - у меня его нет) ушёл в астрал минут 10 назад, по пути несколько раз завалившись на определении имени компа по адресу, не знаю, что там происходит сейчас
И, заодно, я не знаю, как исключительно средствами фрейворка радикально увеличить скорость, разве что wmi, да и тот ведь ни разу не .нет.

Кроме того, вариант с пингом - не самый удачный, пинг может не пропускаться файрволом (впрочем, network discovery сервис может тоже быть вырублен).

Автор: mrbrooks 3.11.2010, 09:46
ping хорош в единичном случае, но использовать его в цикле я бы определенно не стал. на мой взгляд - решение mihryak кошернее, хотя я бы двигался в сторону wmi. 


Цитата(gambit @  2.11.2010,  17:23 Найти цитируемый пост)
Не знаю, может это моя личная неприязнь, но я буду как уж выворачиваться, но на интеропные функции не посмотрю. 

порою от нативных библиотек не уйти. изощренные вывороты могут положить производительность на лопатки.


Автор: Turanda 3.11.2010, 10:42
to mihryak

А где в вашем коде указывается диапазон IP адресов?


P.S. Чет ни как не могу понять :(

А так запустил код, единственное что выдал: Elapsed time: 33342. я не очень долго ждал.

Автор: gambit 3.11.2010, 10:54
Цитата(mihryak @  2.11.2010,  18:58 Найти цитируемый пост)
Ну вот на более серьёзном диапазоне (192.168.0.0-192.168.255.255) у меня компы проверились за 3.5 секунды, а твой вариант (без распараллеливания, правда, - у меня его нет) ушёл в астрал минут 10 назад, по пути несколько раз завалившись на определении имени компа по адресу, не знаю, что там происходит сейчас

Конкретно в данном случае, я не оспариваю, я изначально написал, что идея бредовая. Если возможно, протести пож. вариант с распараллеливанием. По логике он должен быть координально быстрее, так как будут запускаться все новые потоки, которые проц не напрягают, а просто ждут ответа. В случае с одним потоком, он ждет ответ от каждого компа, и только потом отправляет следующему.

Цитата(mrbrooks @  3.11.2010,  09:46 Найти цитируемый пост)
порою от нативных библиотек не уйти. изощренные вывороты могут положить производительность на лопатки.

Это да, но как то душа не лежит(((

Автор: KortenevStas 20.3.2011, 02:37
У меня стоит VS2005. NetworkInformation space не доступно. Надо отдельно Reference подключать?

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)