Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2012.03.11;
Скачать: CL | DM;

Вниз

Проблема с потоками сканирования   Найти похожие ветки 

 
bvv   (2009-09-17 14:57) [0]

Знатоки!
Написал программу сканирования сети.
Для сокращения времени сканирования разбил проверку адресов IP на потоки, если результаты поиска по каждому потоку выводить в свой файл проблем никаких. Если результаты поиска записывать во временный массив простая синхронизации потоков работает только при небольшом количестве потоков. Критические секции немного улучшают ситуацию, но поиск в 256 потоков находит число IP-адресов гораздо больше чем с 1792 потока, переход на Mutex проблемы не решает и оптимальным числом потоков остаётся ~512. Mutex используется только при завершении работы потока для записи результатов поиска в общий массив, да и то, для каждого потока организован свой раздел в массиве, в который нет доступа другим потокам. Процессор двух ядерный.
Всё процессорное время, во время сканирования, съедают Svchost и Acs.
Почему происходят такое различие результатов поиска, если число потоков отличается в три раза, если верить теории этого быть не должно.

С благодарностью Вл.


 
Сергей М. ©   (2009-09-17 15:13) [1]

И куда столько потоков ?
Очуметь же можно - аж под две тысячи)
Хотя для решения задачи с неменьшей эффективностью вполне хватит и дюжины)


 
bvv   (2009-09-17 15:45) [2]

Основное время тратится на ожидание ответа, если сеть класса В и занято много адресов, время сканирования десятки минут, если свободных адресов большая часть это Часы, даде при 512 потоках.


 
Сергей М. ©   (2009-09-17 16:41) [3]


> время тратится на ожидание ответа


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

А пинг-то какими средствами ? raw sockets или wininet-интерфейс ?


 
bvv   (2009-09-17 16:44) [4]

Так ведь я так и делаю, каждый поток пингует свой диапазон адресов.


 
Anatoly Podgoretsky ©   (2009-09-17 16:52) [5]

> bvv  (17.09.2009 16:44:04)  [4]

Не очень верно, пусть поток сканирует только один адрес, тогда быстрее будет. 256 потоков достаточно, для блока С, а к нему можно привести и В и С.
По сути получается почти равное время, что для одного потока.


 
bvv   (2009-09-17 17:03) [6]

Для С сети проблем вообще никаких нет, если В сетку сканировать как последовательный ряд С сетей, судя по всему Вы правы, но тогда каждый раз нужно создавать и гасить новые потоки, а это время. Гораздо проще, весь диапазон разбить на равные отрезки, и на каждый отрезок создать свай поток, это ничему не противоречит, поскольку в каждом потоке не проверяется больше одной станции, и мы не выходим за предельное число потеков в одном процессе, кроме того, если каждый поток записывает результаты поиска в свой файл, тогда здесь даже синхронизация потоков не нужна, всё на Ура проходит.


 
Сергей М. ©   (2009-09-17 17:04) [7]


> каждый поток пингует свой диапазон адресов


А пинговать он должен один адрес, который ему выдаст диспетчер.
Т.е. поток получил адрес, выполнил пинг, отчитался диспетчеру о результатах пинга и ждет получения след.адреса.


 
bvv   (2009-09-17 17:12) [8]

Естественно один, цикл выбирает по одному адресу, и пока не получен ответ на адрес, следующий пинг не начнётся, тоже и с Файлами, но там я для записи результата открывал файл,  записывал и закрывал. с массивом этого делать не нужно а это выигрыш по времени.


 
Сергей М. ©   (2009-09-17 17:24) [9]

На вопрос в [3] ответишь ?


 
bvv   (2009-09-17 17:34) [10]

Сергей, я не не знаю что значит [3] т.к. на форум пришёл впервые, да если честно то и потоками занимаюсь недавно, прочитал и решил модернизировать свою программу, и тут же фэйсом об тэйбол.


 
Сергей М. ©   (2009-09-17 19:34) [11]

При чем здесь потоки ?
Я о пинге, а не о потоках ..


 
bvv   (2009-09-18 08:38) [12]

Сергей, извините, вчере пришлось срочно убегать.
Поиск станци в сети выполняется функцией IPAddrToName
В старой программе для поиска невидимых станций исполь зовался ещё и сокет, но это к делу не относится.


 
Сергей М. ©   (2009-09-18 08:48) [13]


> Поиск станци в сети выполняется функцией IPAddrToName


Что за ерунда ?
Даже по названию ф-ции следует, что она предназначена совсем для иной задачи.
И откуда она у тебя взялась ?
Сдул неглядя из
http://www.google.ru/search?q=IPAddrToName&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:ru:official&client=firefox
?)


> для поиска невидимых станций исполь зовался ещё и сокет


Каких таких "невидимых" ?
И куда делся сокет в "новой программе" ?)


> это к делу не относится


Это к делу относится самым прямым образом.


 
bvv   (2009-09-18 09:30) [14]

Сдул конечно, любая вещь гдде нибудь сдувается дорабатывается и снова сдувается.
Перебирая в цикле адреса определяю наличие станций если есть имя значит есть станция.
Любая проверка наличия станции в сети, так или иначе связана с установкой связи с ней, (если конечно не берётся готовая таблица станций) связь осуществляется соединением по порту, на некоторых станциях может быть запрещён отклик на запрос IPAddrToName, но если станция в сети, значит у неё должен быть открыт как минимум один порт. С помощью сокета можно это зделать, и делалось, но сейчас главной задачей было разобраться с работой потоков, и поиск другиз станций меня пока не интересует. Но в принципе я могу решить задачу сканирования станции обойдясь без всякой синхронизации потоков, просто записывая результаты проверки во временные файлы а после тойже программой считывать сних информацию и обрабатывать её. Это даже решит другую проблему передачи информации из одного процесса в другой без всяких симафоров и Мьютексов, но хотелось разобраться с синхронизацией. Вопрос чисто теоретический, греть процессор никому ненужными синусами для рассмотрения этой проблемы - себя не уважать, вот и занимаюсь извращенияви в сети, а заодно и частично восполню пробел в знаниях.


 
Сергей М. ©   (2009-09-18 09:46) [15]


> если есть имя значит есть станция


Вот уж глупости.
Наличие зарегистрированного в обратной зоне DNS имени хоста ниак не связано с активностью и/или доступностью этого хоста.


> связь осуществляется соединением по порту


Хост не обязан отвечать на запросы на соединение по интересующему тебя порту, равно как и на ping-пакеты, и это ничуть не мешает ему присутствовать в сети.


> на некоторых станциях может быть запрещён отклик на запрос
> IPAddrToName


Эта ф-ция не обращается к "станциям", у нее иное назначение, см.выше (DNS)


> если станция в сети, значит у неё должен быть открыт как
> минимум один порт


С какого это перепугу "должен быть" ?
Это зависит от того как станция сконфигурирована, так что она вовсе не обязана быть чем-то должна твоему сканеру.

Ты пойми главное - не существует и не может существовать ни одного алгоритма, позволяющего со 100%-ной достоверностью определить факт присутствия узла в сети.


 
Сергей М. ©   (2009-09-18 09:49) [16]

Обнаружить в сети хост можно только если этого захочет администратор хоста.
Ну или по недосмотру или раздолбайству этого администратора)


 
Сергей М. ©   (2009-09-18 09:59) [17]


> Сдул конечно


Ну так надо было вникнуть в то что сдул, а не слепо верить в волшебные возможности сдутого)


 
bvv   (2009-09-18 10:02) [18]


> Ты пойми главное - не существует и не может существовать
> ни одного алгоритма, позволяющего со 100%-ной достоверностью
> определить факт присутствия узла в сети.

Так я с этим и не спорю, 100% гарантия может быть только по свершившемуся факту, (Машина врералась в дерево) это может не говорить о причинах свершившегося факта, но он либо есть либо нет.
Я не ставлю перед собой задачу 100% поиска станций, и не собираюсь заниматься их взломом, (Дорожу своим рабочим местом). Я говорю, это чисто теоретический вопрос с синхронизацией большого  числа потоков, поэтому данная функция IPAddrToName меня вполне устраивает, пусть прячутся и правильно делают, а то иногда встречаются станции с расшаренным С диском и даже Program Files нараспашку...
Иногда ставлю их в известность об этом, но чаще просто оставляю как есть, пусть сами разбираются, причём не только у нас но и за бугром такое бывает. Но это уже совсем другая тема...


 
Сергей М. ©   (2009-09-18 10:18) [19]


> функция IPAddrToName меня вполне устраивает


Приведи сюда ее код ..


> теоретический вопрос с синхронизацией большого  числа потоков


Теория при этом абсолютна та же самая, что и теория синхронизации малого числа потоков.
И если у тебя эта синхронизация не работает или работает не так как положено, значит у тебя ошибка в программе.


 
bvv   (2009-09-18 10:41) [20]

function IPAddrToName(IPAddr: string): string;
var
 S: String;
 SockAddrIn: TSockAddrIn;
 HostEnt: PHostEnt;
 WSAData: TWSAData;

 FSocket:TSocket; //Сокет.
 addr:TSockAddr; //Структура адреса.
begin
 S := "";
 WSAStartup($101, WSAData);
 SockAddrIn.sin_addr.s_addr := inet_addr(PChar(IPAddr));
 HostEnt := gethostbyaddr(@SockAddrIn.sin_addr.S_addr, 4, AF_INET);
 if HostEnt <> nil
  then
   begin
    S := StrPas(HostEnt^.h_name);
   end
 else
   begin
    if All
     then
      begin
       WSACleanup;
       addr.sin_family:=AF_INET; //Мутим адресацию, в нашем случае - асинхронная.
       addr.sin_addr.S_addr:=inet_addr(pchar(IPAddr));//Заполняем поле адреса.
       if WSAStartup($101,WSAData)<>0
        then
         begin
          //Если произошла ошибка при старте WinSock выводим сообщение и выходим.
          ShowMessage("ОШИБКА: при старте WinSock. " + IntToStr(GetLastError));
          exit;
         end;

         FSocket:=socket(AF_INET,SOCK_STREAM,0);//Создаем гнездо.
         if FSocket=INVALID_SOCKET
         then
          begin
           //Если если ошибка при создании гнезда то...
           ShowMessage("ОШИБКА: При создании сокета. " + IntToStr(GetLastError));
           exit;
          end;
          addr.sin_port:=htons(PortInvisible);//Присваеваем значению порта текущее значение счетчика.
          index := connect(FSocket,addr,sizeof(addr));
          if index = 0
          then
           begin
            //Ури, открытый порт.
            S := "Порт = " + IntToStr(PortInvisible);
           end;
          CloseSocket(FSocket);
      end; //if Form1.cbInVisible.Checked
    end;   //else
   Result := S;
 WSACleanup;
end;

procedure TThreadScanNet.Execute;
var
 i,k: Cardinal;
 s: string;
 SetM: WORD;
 ii: integer;
Label R;
begin
try
FreeOnTerminate := TRUE;
SetLength(Loc, 0);
with Form1 do
begin
 for k := iBegAddr to iEndAddr do
 begin
   s := IntToStr((k Shr 24) AND $FF) + "." +
        IntToStr((k Shr 16) AND $FF) + "." +
        IntToStr((k Shr 8) AND $FF) + "." +
        IntToStr(k AND $FF);

   s1 := IPAddrToName(s);
   if s1 <> ""
     then
      begin
       j := k;
       NumAdd := NumAdd + 1;
       SetLength(Loc, NumAdd);
       Loc[NumAdd-1].IP := j;
       Loc[NumAdd-1].Name := s1;

{
       SetM := WaitForSingleObject( Scan_Send.Form1.Mutex, INFINITE );
        if SetM = WAIT_OBJECT_0
          then Scan_Send.Form1.NumPc := Scan_Send.Form1.NumPc + 1;
       ReleaseMutex( Scan_Send.Form1.Mutex );
}

{
       EnterCriticalSection(Form1.StringSection); //Ждать освобождения Крит
       Scan_Send.ExZapisNetAddres[Num].NumAdd := Scan_Send.ExZapisNetAddres[Num].NumAdd + 1;
//        Synchronize(ChDate);
       LeaveCriticalSection(Form1.StringSection);
}

      end;
 end;  //for j := iBegAddr to iEndAddr do
end; //with Form1 do
finally
end;

// EnterCriticalSection(Form1.StringSection); //Ждать освобождения Крит

R:
SetM := WaitForSingleObject( Scan_Send.Form1.Mutex, INFINITE );
if SetM = WAIT_OBJECT_0
// if WaitForSingleObject( Scan_Send.Form1.Mutex, 2000 ) = WAIT_OBJECT_0
 then
  begin
   SetLength(Scan_Send.ExZapisNetAddres[Num].Lisp,NumAdd) ;
   Scan_Send.ExZapisNetAddres[Num].NumAdd := NumAdd;
   for ii := 0 to NumAdd - 1 do
    begin
     Scan_Send.ExZapisNetAddres[Num].Lisp[ii].AddNet := Loc[ii].IP;
     Scan_Send.ExZapisNetAddres[Num].Lisp[ii].AddName := Loc[ii].Name;
    end;
    Scan_Send.ExZapisNetAddres[Num].Nit := FALSE;
    Scan_send.NumEndThread := Scan_send.NumEndThread + 1;

    ReleaseMutex( Scan_Send.Form1.Mutex );

  end
 else
  begin
//    ReleaseMutex( Scan_Send.Form1.Mutex );
   Sleep(0);
   goto R;
  end;

//   ReleaseMutex( Scan_Send.Form1.Mutex );

{
 ReleaseMutex( Scan_Send.Form1.Mutex );

 sleep(500);
}
//  Scan_Send.ExZapisNetAddres[Num].ThreadScanNet := TRUE;
//  LeaveCriticalSection(Form1.StringSection); //Освободить Крит
end;


 
Сергей М. ©   (2009-09-18 10:57) [21]

Какой ужас ..

Мало того, что IPAddrToName занимается не тем чем ей положено согласно названию, да еще и бред какой-то:


> Мутим адресацию, в нашем случае - асинхронная


 
bvv   (2009-09-18 11:10) [22]

Я понимаю, но в данном случае эта часть кода не используется, хотя когда эта программа работала без динамического массива, а результат выводился в файл она нисколько не мешала, да и сейчас при работе отключается через  if All
Мешать она никак не может.


 
Сергей М. ©   (2009-09-18 11:16) [23]


> в данном случае эта часть кода не используется


Какая такая "часть кода" не используется ?
Зачем ты приводишь код, который не используется ?
Меня он абсолютно не интересует.
Приводи только актуальный код, без отсебячины и чьих-то бредовых комментарием про "муть".


 
bvv   (2009-09-18 11:21) [24]

function IPAddrToName(IPAddr: string): string;
var
 S: String;
 SockAddrIn: TSockAddrIn;
 HostEnt: PHostEnt;
 WSAData: TWSAData;

 FSocket:TSocket; //Сокет.
 addr:TSockAddr; //Структура адреса.
begin
 S := "";
 WSAStartup($101, WSAData);
 SockAddrIn.sin_addr.s_addr := inet_addr(PChar(IPAddr));
 HostEnt := gethostbyaddr(@SockAddrIn.sin_addr.S_addr, 4, AF_INET);
 if HostEnt <> nil
  then
   begin
    S := StrPas(HostEnt^.h_name);
   End;
   Result := S;
 WSACleanup;
end;


 
Сергей М. ©   (2009-09-18 11:28) [25]

так.
И что конкретно ты ожидаешь от этой функции ?
Опиши как ты себе понимаешь ее работу ..


 
bvv   (2009-09-18 11:42) [26]

struct hostent
{
char FAR * h_name;   // имя хоста
char FAR * FAR * h_aliases;  // дополнительные названия
short h_addrtype;   // тип адреса
short h_length;   // длинна каждого адреса в байтах
char FAR * FAR * h_addr_list; // список адресов
};

Мне нужно имя хоста, если есть имя, значит есть и хост.
Я понимаю, что структуру можно и не получить даже если хост физически работает.


 
Сергей М. ©   (2009-09-18 11:59) [27]


> Мне нужно имя хоста


У хоста может не быть имени, от этого он хостом быть не перестанет.


> если есть имя, значит есть и хост


Нет.
Если есть имя, значит есть адрес хоста, а не хост.

Во-первых, ф-ции gethostbyaddr() нет никакого дела до того, присутствует ли хост в сети в момент ее вызова. Она к интересующему хосту не обращается вообще.

Во-вторых, ф-ция gethostbyaddr() позиционируется в Майкрософт как устаревшая, вместо нее настоятельно рекомендуется использовать протоколонезависимую ф-цию getnameinfo(), хотя суть использования новой или старой функции неизменна.

Так что до синхронизации тебе еще как до Китая - ты в принципе не понимаешь что творишь и как это в действительности работает.


 
bvv   (2009-09-18 12:04) [28]

Спасибо, буду разбираться.
С уважением, В


 
Сергей М. ©   (2009-09-18 12:18) [29]

Простая ассоциация для наведения порядка в голове:
Наличие у тебя или кого-либо в адресной книге (читай - база данных DNS) в мобильном телефоне записи
"Имя: Вася Пупкин (читай - HostName), Телефон: 123456789 (читай - HostAddress)"
не означает:

- что Вася Пупкин жив;
- что у него есть телефон;
- что в телефоне установлена симка именно на номер 123456789;
- что владелец телефона и симки в дан.момент именно Вася Пупкин;
- что телефон этот включен;
- что на этот телефон можно позвонить и дозвониться;
- что ответит именно Вася Пупкин и никто иной.


 
Сергей М. ©   (2009-09-18 12:30) [30]

И еще: за массированное сканирование хостов и сервисов можно и по шее получить от провайдера)


 
bvv   (2009-09-18 12:37) [31]

Хорошо, я понял что запрос идёт на DNS.
Пусть в этом вотросе я полный ноль.
Согласен, это действительно не далеко от истины.

Но, почему при разном сисле потоков получаю разное число хостов, хотя запускаются одновременнодве программы, и таблица хостов на DNS не должна так быстро меняться?
Кроме того, повторное сканирование с малым числом потоков 512 точно повторяет предыдущий результат?
Я понимаю если бы результат сканирования 512 и 1792 потока отличался на единицы, но речь идёт о разах. 3-4 раза
Даже если опрос по этой функции даёт полный бред, то почему в одном случае этот бред повторяется с точностью до хоста, а во втором случае нет.
Почему при сканировании локалки, в которой я живу, она точно называет имена и адреса рабочих станций и серверов?

Я не специалист по сетям, и занимаюсь этим, чтобы не отупеть полностью, и не потерять навыки, поскольку решение систем трансцедентных и дифуравнений, при проектировании физических установок в нашей стране уже давно никого не интересут.


 
Сергей М. ©   (2009-09-18 12:57) [32]


> Почему при сканировании


Да нет у тебя никакого сканирования, что ты заладил про сканирование ?)


> локалки, в которой я живу, она точно называет имена и адреса
> рабочих станций и серверов


Потому что эта инф-ция имеется и доступна в тех DNS-базах, к которым ты осуществляешь обращение при своем т.н. "сканировании".

А рассуждать о какой-то синхронизации сейчас попросту бессмысленно - нет достоверной инф-ции, которую требуется синхронно заносить в аккумулирующий ресурс.

Рекомендую в целях отладки мультипоточного синхронного взаимодействия реализовать эмулятор, который бы не лез в сеть, а возвращал бы данные о хостах из заранее подготовленной локальной таблицы.


 
Сергей М. ©   (2009-09-18 13:01) [33]


> не специалист по сетям


Придется в той или иной минимум необходимой мере им стать, если ты действительно желаешь осознать происходящее.
И это, скажем, не самое худшее лекарство от отупения)


 
bvv   (2009-09-18 13:07) [34]


>
> Придется в той или иной минимум необходимой мере им стать,
>  если ты действительно желаешь осознать происходящее.
> И это, скажем, не самое худшее лекарство от отупения)
> <Цитата>


Соглосен на все сто.

Удачи Вам!
В


 
Сергей М. ©   (2009-09-18 13:09) [35]

Точнее, сканирование-то есть, но сканируешь ты вовсе не то, что заявил в топикстарте: ты просто тупо шаришь по записям доступных тебе DNS-рерурсов.


 
Сергей М. ©   (2009-09-18 13:15) [36]

Ключевой момент, могущий пролить свет на тайну: сетевые DNS-сервисы работают под управлением транспортного протокола UDP, который не гарантирует доставку инф.сообщений от источника к приемнику.
И чем "дальше" от твоего хоста находится хост, предоставляющий DNS-сервис, тем меньше вероятность достоверности получаемых при DNS-запросах данных.


 
bvv   (2009-09-18 13:31) [37]

Да, я читал об UDP и других протоколах, назначение их тоже для меня более или менее ясно, Олифера прочитал и общая картина сети понятна, но теория без практики пустое место, пока своими руками что-то не сделаешь, нечего и говорить о том, что знаешь. Телефонный справочник может быть и интересное чтиво, особенно на ночь, но если нет телефона или некуда звонить...
То же и с сетями, надо пробовать и порверять.
Но потоки всё-таки, можно рассматривать и без глубокого понимания работы сети, мне почему-то так кажется...
Но может быть я не прав.


 
Сергей М. ©   (2009-09-18 14:01) [38]


> потоки всё-таки, можно рассматривать и без глубокого понимания
> работы сети, мне почему-то так кажется


Правильно кажется.
Более того, на этом этапе их следовало бы рассматривать в полном отрыве от сетевой логики.
Т.е. мухи отдельно (потоки, синхронизация и т.д. и т.п.), а котлеты отдельно (сети, протоколы и т.д. и т.п).
И уж только тогда следует сажать мух на котлеты, когда мухи станут большими-злыми-зелеными-осенними, а котлеты будут хорошо прожарены)

О чем я тебе и сказал в [32] (про эмулятор)


 
bvv   (2009-09-18 14:11) [39]

Понял.

До свидания.
Разберусь с сетями вернусь.
Конец связи.
В


 
Anatoly Podgoretsky ©   (2009-09-18 15:25) [40]

> bvv  (17.09.2009 17:12:08)  [8]

Поэтому и неверно вешать блок на один поток, пока он ждет ответа от несуществуеющего ИП, то остальные тоже ждут, а могли бы работать, если бы поток занимался только одним ИП. Результат может быть очень существенным, по сути равным обработке одного потока, даже если все ИП не существуют. Ну а класс С взят просто как удобная величина, поскольку обычно пингуют не больше одного класса за раз, на самом деле никакой связи с классами нет, это может произвольный список и количество потоков не обязательно 256, может эффективнее будет 512. Все будет зависить от количества адресов. Но и в этом случае один поток может обслужить 100 адресов, пока другой поток ждет ответа. И не надо потоки постоянно создавать разрушать, достаточно пула потоков.



Страницы: 1 2 вся ветка

Текущий архив: 2012.03.11;
Скачать: CL | DM;

Наверх




Память: 0.6 MB
Время: 0.009 c
6-1253185020
bvv
2009-09-17 14:57
2012.03.11
Проблема с потоками сканирования


15-1321475403
Юрий
2011-11-17 00:30
2012.03.11
С днем рождения ! 17 ноября 2011 четверг


15-1321736064
Германн
2011-11-20 00:54
2012.03.11
Бродил тут


2-1321966512
jacksotnik
2011-11-22 16:55
2012.03.11
Картинка в mysql


15-1321442171
OW
2011-11-16 15:16
2012.03.11
есть ли в природе какой старый FastReport? бесплатный, с сорцами