2011-02-03 16 views
7

Inspecciono muchos dispositivos en la red (más de 300) mediante ping iterativo.¿Cuál es la mejor manera de hacer ping a muchos dispositivos de red en paralelo?

El programa sondea los dispositivos secuencialmente, por lo que es lento. Me gustaría mejorar la velocidad de las encuestas.

Hay algunas maneras de hacer esto en Delphi 7:

  1. cada dispositivo tiene un hilo haciendo ping. Administrar hilos manualmente
  2. Aprende y usa Indy 10. Necesito ejemplos.
  3. Utilice las E/S superpuestas en función de los mensajes de la ventana.
  4. Utilice puertos de finalización basados ​​en eventos.

¿Qué es más rápido, más fácil? Por favor, brinde algunos ejemplos o enlaces, por ejemplo.

+0

tengo una herramienta similar. es solo un montón de hilos esperando respuestas de eco ICMP. –

+0

Si saca suficientes pings, activará los sistemas de detección de intrusos. –

Respuesta

9

Inundar la red con ICMP no es una buena idea.

Es posible que desee considerar algún tipo de grupo de subprocesos y poner en cola las solicitudes de ping y tener un número fijo de subprocesos haciendo las solicitudes.

+14

Ah, los recuerdos. Un compañero de trabajo preguntó una vez, casi conversacionalmente, "¿cómo puedo enviar varios sonidos al mismo tiempo?" Mi breve respuesta fue "ponerlos en hilos". Media hora después recibimos a un administrador de sistemas que se precipitó en nuestra oficina gritando que estaba "pirateando" nuestra red. –

+0

+1 para DOS autoinfligido, y +1 a la historia de guerra de Leonardo. Quiéralo. –

+2

A partir de la pregunta original, es obvio que el interlocutor ya hace el ping (en serie actualmente) por lo que decirle que no debe hacer lo que ya está haciendo (y parece que tiene que hacer) no es realmente productivo. –

3

¿Necesita una respuesta de cada máquina en la red, o son estas 300 máquinas solo un subconjunto de la red más grande?

Si necesita una respuesta de cada máquina, usted podría considerar el uso de un broadcast address o multicast address para su solicitud de eco.

+0

Los dispositivos están ubicados en muchos grupos y cada grupo tiene su propia subred. –

+0

Bueno, también puedes transmitir a subredes. Mi punto era principalmente que si había muchas máquinas de las que ** no ** querías una respuesta, entonces este método sería ineficiente. – Leigh

5

El acceso directo ICMP está en desuso en Windows. El acceso directo al protocolo ICMP en Windows está controlado. Debido al uso malicioso de los zócalos sin procesar del estilo ICMP/ping/traceroute, creo que en algunas versiones de Windows necesitará usar la API propia de Windows. Windows XP, Vista y Windows 7, en particular, no permiten que los programas de usuario accedan a sockets sin formato.

He utilizado la funcionalidad enlatada en ICMP.dll, que es lo que hacen algunos componentes Delphi ping, pero un comentario a continuación me alertó sobre el hecho de que esto se considera "usar una interfaz API no documentada".

He aquí una muestra de la componente principal delphi de ping llamarse a sí misma:

function TICMP.ping: pIcmpEchoReply; 
{var } 
begin 
    // Get/Set address to ping 
    if ResolveAddress = True then begin 
    // Send packet and block till timeout or response 
    _NPkts := _IcmpSendEcho(_hICMP, _Address, 
          _pEchoRequestData, _EchoRequestSize, 
          @_IPOptions, 
          _pIPEchoReply, _EchoReplySize, 
          _TimeOut); 
    if _NPkts = 0 then begin 
     result := nil; 
     status := CICMP_NO_RESPONSE; 
    end else begin 
     result := _pIPEchoReply; 
    end; 
    end else begin 
    status := CICMP_RESOLVE_ERROR; 
    result := nil; 
    end; 
end; 

creo que la mayoría de las implementaciones de componentes Ping modernos van a estar basado en un poco similar de código a la de arriba, y tengo lo usé para ejecutar esta operación de ping en una cadena de fondo, sin ningún tipo de análisis. (Programa de demostración incluido en el enlace a continuación).

El código fuente de muestra completo para la demo basada en ICMP.DLL es here.

ACTUALIZACIÓN Una muestra Iphlpapi.dll más moderno se encuentra en About.com here.

+1

'icmp.dll' no estaba documentado. Por otro lado ** IP Helper API ** ('Iphlpapi.dll') está documentado, con la función' IcmpSendEcho' (http://msdn.microsoft.com/en-us/library/aa366050(v=VS. 85) .aspx) –

+0

Estoy usando la implementación de Iphlpapi.dll. –

+0

Gracias por la información sobre Iphlpapi.dll. –

6

Personalmente me gustaría ir con IOCP. Estoy usando eso con mucho éxito para la implementación del transporte en NexusDB.

Si desea realizar 300 ciclos de envío/recepción utilizando sockets de bloqueo e hilos en paralelo, necesita 300 hilos.

Con IOCP, después de haber asociado los sockets con el IOCP, puede realizar las 300 operaciones de envío y regresarán instantáneamente antes de que se complete la operación. A medida que se completen las operaciones, los llamados paquetes de finalización se pondrán en cola para el IOCP. Luego tiene un grupo de subprocesos esperando en el IOCP, y el SO los despierta a medida que ingresan los paquetes de finalización. Como reacción a las operaciones de envío completadas, puede realizar las operaciones de recepción. Las operaciones de recepción también regresan instantáneamente y, una vez que se completan, se ponen en cola para el IOCP.

Lo realmente especial de un IOCP es que sabe qué hilos le pertenecen y actualmente está procesando paquetes de finalización. Y el IOCP solo activa nuevos subprocesos si el número total de subprocesos activos (no en estado de espera de modo kernel) es menor que el número de simultaneidad de IOCP (por defecto es igual al número de núcleos lógicos disponibles en la máquina). Además, si hay subprocesos esperando paquetes de finalización en el IOCP (que aún no se han iniciado a pesar de que los paquetes de finalización se pusieron en cola porque el número de subprocesos activos era igual al número de coincidencia), el momento uno de los subprocesos que se está procesando actualmente un paquete de finalización entra en un estado de espera del modo kernel por cualquier razón, se inicia uno de los subprocesos en espera.

Temas que vuelven a los paquetes de finalización de recogida de IOCP en orden LIFO. Es decir, si un hilo está volviendo al IOCP y todavía hay paquetes de finalización esperando, ese hilo recoge directamente el siguiente paquete de finalización, en lugar de ponerlo en estado de espera y el hilo que espera durante más tiempo se despierta.

En condiciones óptimas, tendrá un número de subprocesos igual al número de núcleos disponibles que se ejecutan simultáneamente (uno en cada núcleo), seleccionando el siguiente paquete de finalización, procesándolo, volviendo al IOCP y seleccionando directamente el siguiente paquete de finalización, todo sin entrar nunca en un estado de espera del modo kernel o teniendo que tener lugar un cambio de contexto de hilo. Si tuviera 300 hilos y operaciones de bloqueo, no solo desperdiciaría al menos 300 MB de espacio de direcciones (para el espacio reservado para las pilas), sino que también tendría conmutadores de contexto de hilo constantes a medida que un hilo entra en una estado de espera (esperando que se complete un envío o recepción) y el siguiente hilo con un envío completo o recibir un despertar. - Thorsten Engler hace 12 horas

+0

¿Puedes ampliar eso? ¿De qué manera IO Completion Ports lo ayuda a hacer ping? Todo lo que Ping hace es decir "sí, soy un dispositivo de red, y he decidido reconocer que estoy aquí, porque nadie deshabilitó las respuestas de solicitud de ICMP en este dispositivo". Si usó puertos de terminación, ¿no necesitaría también utilizar sockets sin formato para hacer funcionar su propio ICMP? ¿Y no están bloqueados los conectores crudos en Win XP/7/Vista? –

+0

Thorsten: información útil, ¡pero esta debería ser la respuesta en sí! "IOCP" puede no significar nada para el consultante original sin un enlace o algo así, ayuda si las respuestas contienen un poco más de detalle. Puede editar su respuesta para actualizarla. –

+0

@David M, el autor de la pregunta original en la lista "Usar puertos de finalización basados ​​en eventos". Eso es IOCP (= puerto de finalización de E/S). Por lo tanto, parecía bastante claro que el consultante original conoce los IOCP. Pero ahora he movido los comentarios a la respuesta real. Gracias por señalar eso. –

4

Aquí hay un article from Delphi3000 que muestra cómo usar IOCP para crear un grupo de subprocesos. No soy el autor de este código, pero la información del autor está en el código fuente.

Estoy re-publicar los comentarios y código aquí:

Todo el mundo debe entender ahora por qué un hilo es, los principios de hilos y así sucesivamente. Para aquellos en necesidad, la función simple de un hilo es procesamiento separado de un hilo a otro, para permitir la ejecución simultánea y en paralelo. El principio principal de hilos es igual de simple, la memoria asignada que se hace referencia entre hilos se deben reunir para garantizar seguridad de acceso. Hay un número de otros principios, pero esto es realmente el que debe importar.

Y en ..

Un hilo de cola de seguro permitirá varios subprocesos para agregar y quitar, de inserción y extracción de los valores y de la cola con seguridad en un primer lugar en primer lugar base. Con una cola escrita eficiente y bien puede tener un componente muy útil en el desarrollo de aplicaciones con rosca , desde ayudar a con registro seguro de subprocesos, hasta procesamiento asincrónico de solicitudes.

un grupo de subprocesos es simplemente un hilo o un número de hilos que son la mayoría comúnmente utilizado para gestionar una cola de peticiones. Por ejemplo, un servidor web que tendría una cola continua de solicitudes que necesitan ser procesados ​​uso agrupaciones de hebras para gestionar el http solicitudes, o una COM + o servidor DCOM utiliza un grupo de subprocesos para manejar la RPC peticiones. Esto se hace por lo que no es un menor impacto de la transformación de una petición a otro, por ejemplo si se ejecutó 3 peticiones de forma sincrónica y la primera solicitud tomó 1 minuto para completar, los segundo dos peticiones no completarían durante al menos 1 minuto agregando en la parte superior tiene tiempo para procesar, y para la mayoría de los clientes esto no es aceptable.

Entonces, ¿cómo hacer esto ..

A partir de la cola !!

Delphi hace proporciona un objeto TQUEUE cuales está disponible, pero es por desgracia no hilo de seguridad ni realmente muy eficiente, pero la gente debe buscar en el archivo a Contnrs.pas ver cómo Borland escritura hay pilas y colas . Solo hay dos funciones principales de requeridas para una cola, estas son add y remove/push y pop. Add/push agregará un valor, un puntero o un objeto al final de una cola. Y remove/pop eliminará y devolverá el primer valor en la cola.

Se podría derivar de TQUEUE objeto y anular los métodos protegidos y añadir en las secciones críticas, esto obtener una parte del camino, pero me que mi cola para esperar hasta que los nuevos solicitudes están en la cola y poner el subproceso en estado de reposo mientras espera nuevas solicitudes. Esto podría ser hecho al agregar en Mutexes o eventos de señalización , pero hay una manera más fácil. La aplicación de Windows proporciona una cola de finalización IO que nos proporciona el hilo de seguridad acceso seguro a una cola y un estado de mientras espera la nueva solicitud en la cola.

La implementación de la agrupación de hebras

La piscina hilo va a ser muy simple y gestionará x número de hilos deseados y pasar cada cola de solicitudes de a un evento proporcionado para ser procesado. Rara vez hay una necesidad de implementar una clase TThread y su lógica de para ser implementado y encapsulado dentro del evento ejecutar de la clase, por lo que un simple clase TSimpleThread se puede crear que ejecutará cualquier método de cualquier objeto dentro el contexto de otro hilo . Una vez que las personas entiendan esto, todo lo que necesita para preocuparse por se le asigna memoria.

Así es como se implementa.

TThreadQueue y TThreadPool aplicación

(* Implemented for Delphi3000.com Articles, 11/01/2004 
     Chris Baldwin 
     Director & Chief Architect 
     Alive Technology Limited 
     http://www.alivetechnology.com 
*) 
unit ThreadUtilities; 

uses Windows, SysUtils, Classes; 

type 
    EThreadStackFinalized = class(Exception); 
    TSimpleThread = class; 

    // Thread Safe Pointer Queue 
    TThreadQueue = class 
    private 
     FFinalized: Boolean; 
     FIOQueue: THandle; 
    public 
     constructor Create; 
     destructor Destroy; override; 
     procedure Finalize; 
     procedure Push(Data: Pointer); 
     function Pop(var Data: Pointer): Boolean; 
     property Finalized: Boolean read FFinalized; 
    end; 

    TThreadExecuteEvent = procedure (Thread: TThread) of object; 

    TSimpleThread = class(TThread) 
    private 
     FExecuteEvent: TThreadExecuteEvent; 
    protected 
     procedure Execute(); override; 
    public 
     constructor Create(CreateSuspended: Boolean; ExecuteEvent: TThreadExecuteEvent; AFreeOnTerminate: Boolean); 
    end; 

    TThreadPoolEvent = procedure (Data: Pointer; AThread: TThread) of Object; 

    TThreadPool = class(TObject) 
    private 
     FThreads: TList; 
     FThreadQueue: TThreadQueue; 
     FHandlePoolEvent: TThreadPoolEvent; 
     procedure DoHandleThreadExecute(Thread: TThread); 
    public 
     constructor Create(HandlePoolEvent: TThreadPoolEvent; MaxThreads: Integer = 1); virtual; 
     destructor Destroy; override; 
     procedure Add(const Data: Pointer); 
    end; 

implementation 

{ TThreadQueue } 

constructor TThreadQueue.Create; 
begin 
    //-- Create IO Completion Queue 
    FIOQueue := CreateIOCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0); 
    FFinalized := False; 
end; 

destructor TThreadQueue.Destroy; 
begin 
    //-- Destroy Completion Queue 
    if (FIOQueue <> 0) then 
     CloseHandle(FIOQueue); 
    inherited; 
end; 

procedure TThreadQueue.Finalize; 
begin 
    //-- Post a finialize pointer on to the queue 
    PostQueuedCompletionStatus(FIOQueue, 0, 0, Pointer($FFFFFFFF)); 
    FFinalized := True; 
end; 

(* Pop will return false if the queue is completed *) 
function TThreadQueue.Pop(var Data: Pointer): Boolean; 
var 
    A: Cardinal; 
    OL: POverLapped; 
begin 
    Result := True; 
    if (not FFinalized) then 
//-- Remove/Pop the first pointer from the queue or wait 
     GetQueuedCompletionStatus(FIOQueue, A, Cardinal(Data), OL, INFINITE); 

    //-- Check if we have finalized the queue for completion 
    if FFinalized or (OL = Pointer($FFFFFFFF)) then begin 
     Data := nil; 
     Result := False; 
     Finalize; 
    end; 
end; 

procedure TThreadQueue.Push(Data: Pointer); 
begin 
    if FFinalized then 
     Raise EThreadStackFinalized.Create('Stack is finalized'); 
    //-- Add/Push a pointer on to the end of the queue 
    PostQueuedCompletionStatus(FIOQueue, 0, Cardinal(Data), nil); 
end; 

{ TSimpleThread } 

constructor TSimpleThread.Create(CreateSuspended: Boolean; 
    ExecuteEvent: TThreadExecuteEvent; AFreeOnTerminate: Boolean); 
begin 
    FreeOnTerminate := AFreeOnTerminate; 
    FExecuteEvent := ExecuteEvent; 
    inherited Create(CreateSuspended); 
end; 

procedure TSimpleThread.Execute; 
begin 
    if Assigned(FExecuteEvent) then 
     FExecuteEvent(Self); 
end; 

{ TThreadPool } 

procedure TThreadPool.Add(const Data: Pointer); 
begin 
    FThreadQueue.Push(Data); 
end; 

constructor TThreadPool.Create(HandlePoolEvent: TThreadPoolEvent; 
    MaxThreads: Integer); 
begin 
    FHandlePoolEvent := HandlePoolEvent; 
    FThreadQueue := TThreadQueue.Create; 
    FThreads := TList.Create; 
    while FThreads.Count < MaxThreads do 
     FThreads.Add(TSimpleThread.Create(False, DoHandleThreadExecute, False)); 
end; 

destructor TThreadPool.Destroy; 
var 
    t: Integer; 
begin 
    FThreadQueue.Finalize; 
    for t := 0 to FThreads.Count-1 do 
     TThread(FThreads[t]).Terminate; 
    while (FThreads.Count > 0) do begin 
     TThread(FThreads[0]).WaitFor; 
     TThread(FThreads[0]).Free; 
     FThreads.Delete(0); 
    end; 
    FThreadQueue.Free; 
    FThreads.Free; 
    inherited; 
end; 

procedure TThreadPool.DoHandleThreadExecute(Thread: TThread); 
var 
    Data: Pointer; 
begin 
    while FThreadQueue.Pop(Data) and (not TSimpleThread(Thread).Terminated) do begin 
     try 
      FHandlePoolEvent(Data, Thread); 
     except 
     end; 
    end; 
end; 

end. 

Como se puede ver que es bastante recta hacia adelante, y con esto se puede aplicar muy fácilmente ninguna cola de solicitudes sobre las roscas y realmente cualquier tipo de requisito que requiera puede hacerse usando estos objeto ys Le ofrecemos mucho tiempo y esfuerzo .

Usted puede usar esto para cola las solicitudes de un subproceso a múltiples hilos, o cola de peticiones de múltiples hilos abajo a un hilo que hace que este una solución bastante agradable.

Aquí hay algunos ejemplos del uso de estos objetos .

Tema tala segura

para permitir que varios hilos para escribir de forma asíncrona a un archivo de registro .

uses Windows, ThreadUtilities,...; 

type 
    PLogRequest = ^TLogRequest; 
    TLogRequest = record 
     LogText: String; 
    end; 

    TThreadFileLog = class(TObject) 
    private 
     FFileName: String; 
     FThreadPool: TThreadPool; 
     procedure HandleLogRequest(Data: Pointer; AThread: TThread); 
    public 
     constructor Create(const FileName: string); 
     destructor Destroy; override; 
     procedure Log(const LogText: string); 
    end; 

implementation 

(* Simple reuse of a logtofile function for example *) 
procedure LogToFile(const FileName, LogString: String); 
var 
    F: TextFile; 
begin 
    AssignFile(F, FileName); 
    if not FileExists(FileName) then 
     Rewrite(F) 
    else 
     Append(F); 
    try 
     Writeln(F, DateTimeToStr(Now) + ': ' + LogString); 
    finally 
     CloseFile(F); 
    end; 
end; 

constructor TThreadFileLog.Create(const FileName: string); 
begin 
    FFileName := FileName; 
    //-- Pool of one thread to handle queue of logs 
    FThreadPool := TThreadPool.Create(HandleLogRequest, 1); 
end; 

destructor TThreadFileLog.Destroy; 
begin 
    FThreadPool.Free; 
    inherited; 
end; 

procedure TThreadFileLog.HandleLogRequest(Data: Pointer; AThread: TThread); 
var 
    Request: PLogRequest; 
begin 
    Request := Data; 
    try 
     LogToFile(FFileName, Request^.LogText); 
    finally 
     Dispose(Request); 
    end; 
end; 

procedure TThreadFileLog.Log(const LogText: string); 
var 
    Request: PLogRequest; 
begin 
    New(Request); 
    Request^.LogText := LogText; 
    FThreadPool.Add(Request); 
end; 

ya que este es el registro en un archivo que se proceso de todas las solicitudes a un solo hilo, pero que podría ser rica correo electrónico notificaciones con un mayor número de hilos , o mejor aún, proceso perfil con lo que está pasando o pasos en su programa que voy a demostrar en otro artículo como este uno tiene bastante tiempo ahora.

Por ahora te dejo con esto, disfruta .. Deja un comentario si hay cualquier cosa que la gente tenga.

Chris

+1

Encontré un motor IOCP http://voipobjects.com/index.php?page=IOCP-engine. El enlace encontrado en http://stackoverflow.com/questions/2302267/is-there-a-i-o-completion-port-based-component-for-delphi –

2

Por favor, dar una oportunidad en "chknodes" ping paralelo para Linux que enviará un solo ping para todos los nodos de la red. También hará una búsqueda inversa en dns y solicitará la respuesta http si así se especifica. Está escrito completamente en bash, es decir, puedes verificarlo fácilmente o modificarlo según tus necesidades. Aquí está una copia impresa de ayuda:

chknodes -h

chknodes ---- rápida de ping paralelo

chknodes [-l | --log] [-h | --help] [-H | --http] [-u | --uninstall] [-v | --version] [-V | --verbose]

-l | --log Log to file -h | --help Muestra esta pantalla de ayuda -H | --http Verifique también la respuesta HTTP -n | - nombres Obtener también nombres de host -u | --uninstall Eliminar instalación -v | --version Mostrar la versión -V | --verbose Mostrar cada dirección IP ping

Es necesario ejecutar para dar adecuado para ello (como con cualquier/script sh bash) con el fin de ejecutarlo:

chmod +x chknodes 

En la primera carrera, es decir

./chknodes 

se le sugerirá que se instale a// bin/chknodes usr/local, después de que la administración solo

chknodes 

será suficiente. Lo puedes encontrar aquí:

www.homelinuxpc.com/download/chknodes

Cuestiones relacionadas