![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Проблема с потоками сканирования [WinXP]
bvv © (2009-09-17 14:57:00)Знатоки!
Написал программу сканирования сети.
Для сокращения времени сканирования разбил проверку адресов IP на потоки, если результаты поиска по каждому потоку выводить в свой файл проблем никаких. Если результаты поиска записывать во временный массив простая синхронизации потоков работает только при небольшом количестве потоков. Критические секции немного улучшают ситуацию, но поиск в 256 потоков находит число IP-адресов гораздо больше чем с 1792 потока, переход на Mutex проблемы не решает и оптимальным числом потоков остаётся ~512. Mutex используется только при завершении работы потока для записи результатов поиска в общий массив, да и то, для каждого потока организован свой раздел в массиве, в который нет доступа другим потокам. Процессор двух ядерный.
Всё процессорное время, во время сканирования, съедают Svchost и Acs.
Почему происходят такое различие результатов поиска, если число потоков отличается в три раза, если верить теории этого быть не должно.
С благодарностью Вл.
bvv (2009-09-18 11:42:00) [21]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:28:00) [22]так.
И что конкретно ты ожидаешь от этой функции ?
Опиши как ты себе понимаешь ее работу ..
bvv (2009-09-18 11:21:00) [23]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:16:00) [24]
> в данном случае эта часть кода не используется
Какая такая "часть кода" не используется ?
Зачем ты приводишь код, который не используется ?
Меня он абсолютно не интересует.
Приводи только актуальныйкод, без отсебячины и чьих-то бредовых комментарием про "муть".
bvv (2009-09-18 11:10:00) [25]Я понимаю, но в данном случае эта часть кода не используется, хотя когда эта программа работала без динамического массива, а результат выводился в файл она нисколько не мешала, да и сейчас при работе отключается через if All
Мешать она никак не может.
Сергей М. (2009-09-18 10:57:00) [26]Какой ужас ..
Мало того, что IPAddrToName занимается не тем чем ей положено согласно названию, да еще и бред какой-то:
> Мутим адресацию, в нашем случае - асинхронная
bvv (2009-09-18 10:41:00) [27]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:18:00) [28]
> функция IPAddrToName меня вполне устраивает
Приведи сюда ее код ..
> теоретический вопрос с синхронизацией большого числа потоков
Теория при этом абсолютна та же самая, что и теория синхронизации малого числа потоков.
И если у тебя эта синхронизация не работает или работает не так как положено, значит у тебя ошибка в программе.
bvv (2009-09-18 10:02:00) [29]
> Ты пойми главное - не существует и не может существовать
> ни одного алгоритма, позволяющего со 100%-ной достоверностью
> определить факт присутствия узла в сети.
Так я с этим и не спорю, 100% гарантия может быть только по свершившемуся факту, (Машина врералась в дерево) это может не говорить о причинах свершившегося факта, но он либо есть либо нет.
Я не ставлю перед собой задачу 100% поиска станций, и не собираюсь заниматься их взломом, (Дорожу своим рабочим местом). Я говорю, это чисто теоретический вопрос с синхронизацией большого числа потоков, поэтому данная функция IPAddrToName меня вполне устраивает, пусть прячутся и правильно делают, а то иногда встречаются станции с расшаренным С диском и даже Program Files нараспашку...
Иногда ставлю их в известность об этом, но чаще просто оставляю как есть, пусть сами разбираются, причём не только у нас но и за бугром такое бывает. Но это уже совсем другая тема...
Сергей М. (2009-09-18 09:59:00) [30]
> Сдул конечно
Ну так надо было вникнуть в то что сдул, а не слепо верить в волшебные возможности сдутого)
Сергей М. (2009-09-18 09:49:00) [31]Обнаружить в сети хост можно только если этого захочет администратор хоста.
Ну или по недосмотру или раздолбайству этого администратора)
Сергей М. (2009-09-18 09:46:00) [32]
> если есть имя значит есть станция
Вот уж глупости.
Наличие зарегистрированного в обратной зоне DNSимени хоста ниак не связано с активностью и/или доступностью этого хоста.
> связь осуществляется соединением по порту
Хост не обязан отвечать на запросы на соединение по интересующему тебя порту, равно как и на ping-пакеты, и это ничуть не мешает ему присутствовать в сети.
> на некоторых станциях может быть запрещён отклик на запрос
> IPAddrToName
Эта ф-ция необращается к "станциям", у нее иноеназначение, см.выше (DNS)
> если станция в сети, значит у неё должен быть открыт как
> минимум один порт
С какого это перепугу "должен быть" ?
Это зависит от того как станция сконфигурирована, так что она вовсе не обязана быть чем-то должна твоему сканеру.
Ты пойми главное- несуществует и неможет существовать ниодного алгоритма, позволяющего со 100%-ной достоверностью определить факт присутствия узла в сети.
bvv (2009-09-18 09:30:00) [33]Сдул конечно, любая вещь гдде нибудь сдувается дорабатывается и снова сдувается.
Перебирая в цикле адреса определяю наличие станций если есть имя значит есть станция.
Любая проверка наличия станции в сети, так или иначе связана с установкой связи с ней, (если конечно не берётся готовая таблица станций) связь осуществляется соединением по порту, на некоторых станциях может быть запрещён отклик на запрос IPAddrToName, но если станция в сети, значит у неё должен быть открыт как минимум один порт. С помощью сокета можно это зделать, и делалось, но сейчас главной задачей было разобраться с работой потоков, и поиск другиз станций меня пока не интересует. Но в принципе я могу решить задачу сканирования станции обойдясь без всякой синхронизации потоков, просто записывая результаты проверки во временные файлы а после тойже программой считывать сних информацию и обрабатывать её. Это даже решит другую проблему передачи информации из одного процесса в другой без всяких симафоров и Мьютексов, но хотелось разобраться с синхронизацией. Вопрос чисто теоретический, греть процессор никому ненужными синусами для рассмотрения этой проблемы - себя не уважать, вот и занимаюсь извращенияви в сети, а заодно и частично восполню пробел в знаниях.
Сергей М. (2009-09-18 08:48:00) [34]
> Поиск станци в сети выполняется функцией 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 08:38:00) [35]Сергей, извините, вчере пришлось срочно убегать.
Поиск станци в сети выполняется функцией IPAddrToName
В старой программе для поиска невидимых станций исполь зовался ещё и сокет, но это к делу не относится.
Сергей М. (2009-09-17 19:34:00) [36]При чем здесь потоки ?
Я о пинге, а не о потоках ..
bvv (2009-09-17 17:34:00) [37]Сергей, я не не знаю что значит [3] т.к. на форум пришёл впервые, да если честно то и потоками занимаюсь недавно, прочитал и решил модернизировать свою программу, и тут же фэйсом об тэйбол.
Сергей М. (2009-09-17 17:24:00) [38]На вопрос в [3] ответишь ?
bvv (2009-09-17 17:12:00) [39]Естественно один, цикл выбирает по одному адресу, и пока не получен ответ на адрес, следующий пинг не начнётся, тоже и с Файлами, но там я для записи результата открывал файл, записывал и закрывал. с массивом этого делать не нужно а это выигрыш по времени.
Сергей М. (2009-09-17 17:04:00) [40]
> каждый поток пингует свой диапазон адресов
А пинговать он должен одинадрес, который ему выдаст диспетчер.
Т.е. поток получил адрес, выполнил пинг, отчитался диспетчеру о результатах пинга и ждет получения след.адреса.