23 abril 2010

La librería Synapse (4)

El protocolo SNMP (Simple Network Management Protocol) facilita el intercambio de información entre distintos dispositivos de red a la hora de mandarse información sobre su configuración. Este protocolo utiliza UDP para solicitar la información al servidor.

Por ejemplo, podemos utilizar este protocolo para que los clientes de un programa le pidan al servidor que puerto se utiliza para atacar al motor de bases de datos, aunque generalmente se suele utilizar para configuraciones de routers, impresoras, servidores, etc.

Para que un cliente le pueda pedir algún dato al servidor se utiliza un identificador de objeto llamado MIB que viene definido en este árbol (clic para ampliar):

En el ejemplo que trae la librería Synapse utiliza el identificador 1.3.6.1.2.1.1.1.0, lo que quiere decir que es un objeto ISO, que pertenece a una organización identificada, DOD, Internet, etc. Es decir, vamos siguiendo las ramas del árbol según los dispositivos que van a comunicarse. Para más información sobre SNMP:

http://es.wikipedia.org/wiki/Simple_Network_Management_Protocol

CREAR UN SERVIDOR SNMP

Nuestro servidor va a tener un solo formulario con un componente Memo llamado Mensajes donde escribiremos lo que pasa en el servidor:

Para poder vincularnos con la librería de Synapse entonces debemos añadir al formulario las unidades:

blcksock, winsock, Synautil, SNMPSend, asn1util;

Al igual que los servidores que implementamos anteriormente, nuestro servidor será un hilo de ejecución que escucha por el puerto 161 las peticiones de valores de los clientes:

THiloSNMP = class(TThread)
private
Sock: TUDPBlockSocket;
SNMPRec: TSNMPRec;
sMensaje: string;
public
constructor Create;
destructor Destroy; override;
procedure Execute; override;
procedure ProcessSnmpRequest(PDU: integer; var sOID, sValor: string;
var iTipoValor: Integer);
procedure Monitorizar;
end;

Al crear el constructor creamos el Sock de conexión y el objeto SNMPRec que recogerá las peticiones de los clientes:

constructor THiloSNMP.Create;
begin
Sock := TUDPBlockSocket.Create;
SNMPRec := TSNMPRec.Create;
FreeOnTerminate := True;
inherited Create(False);
end;

No debemos olvidar de destruirlo todo:

Destructor THiloSNMP.Destroy;
begin
Sock.Free;
SNMPREC.Free;
inherited Destroy;
end;

Al poner en marcha el servidor, queda indefinidamente esperando peticiones de valores de los clientes hasta que lo cerremos:

procedure THiloSNMP.Execute;
var
sBuffer: string;
n: integer;
mib: TSNMPMib;
sOID, sValor: string;
iTipoValor: Integer;
begin
with Sock do
begin
Bind('0.0.0.0', '161');

if Sock.LastError <> 0 then
Exit;

repeat
if Terminated then
Break;

sBuffer := Sock.RecvPacket(1000);

if Sock.LastError = 0 then
begin
SNMPRec.Clear;
SNMPRec.DecodeBuf(sBuffer);

for n := 0 to SNMPRec.MIBCount - 1 do
begin
mib := SNMPRec.MIBByIndex(n);

if mib <> nil then
begin
sOID := mib.OID;
sValor := mib.Value;
iTipoValor := mib.ValueType;
ProcessSnmpRequest(SNMPRec.PDUType, sOID, sValor, iTipoValor);
mib.OID := sOID;
mib.Value := sValor;
mib.ValueType := iTipoValor;
end;
end;

SNMPRec.PDUType := PDUGetResponse;
SNMPRec.ErrorStatus := 0;
sBuffer := SNMPRec.EncodeBuf;
Sock.SendString(sBuffer);
end;

until False;
end;
end;

Cuando el servidor recibe el objeto identificador del cliente MIB, lee el identificador del valor OID y genera una respuesta con el método ProcessSnmpRequest:

procedure THiloSNMP.ProcessSnmpRequest(PDU: integer; var sOID, sValor: string;
var iTipoValor: Integer);
begin
if PDU = PDUGetRequest then
begin
sMensaje := 'Solicitan: ' + sOID;
Synchronize(Monitorizar);

// Si no tenemos respuesta, devolvemos una predeterminada
sValor := 'No lo se';

if sOID = '1.3.6.1.2.1.1.1.0' then
begin
sValor := 'Valor devuelto por el servidor';
iTipoValor := ASN1_OCTSTR;
end;

sMensaje := 'Respondiendo: ' + sValor;
Synchronize(Monitorizar);
end;
end;

Para poder sacar por pantalla los mensajes del servidor utilizamos el método Monitorizar para poder sincronizarnos con el formulario principal a través del hilo de ejecución:

procedure THiloSNMP.Monitorizar;
begin
FServidorSNMP.Mensajes.Lines.Add(sMensaje);
end;

Por último, en creamos y destruimos el servidor SNMP al crear o destruir el formulario:

procedure TFServidorSNMP.FormCreate(Sender: TObject);
begin
Mensajes.Lines.Add('Arrando servidor SNMP por el puerto 161...');
HiloSNMP := THiloSNMP.Create;
end;

procedure TFServidorSNMP.FormDestroy(Sender: TObject);
begin
HiloSNMP.Terminate;
end;

Ahora vamos a crear el cliente que le pide los datos.

CREAR UN CLIENTE SNMP

El cliente de SNMP es mucho más fácil de crear que el servidor. Tenemos que añadir la unidad SNMPSend al siguiente formulario:

Se compone de los componentes TEdit llamados IP y OID para solicitar el valor al servidor y la respuesta irá a parar al componente TMemo llamado Respuesta. El campo Comunidad lo necesita la función SNMPGet como parámetro:

procedure TFClienteSNMP.BPedirClick(Sender: TObject);
var
sRespuesta: string;
begin
SNMPget(OID.Text, Comunidad.Text, IP.Text, sRespuesta);
Respuesta.Lines.Text := sRespuesta;
end;

Ahora ponemos en marcha el servidor:

Ejecutamos el cliente, escribimos la dirección 127.0.0.1 y pulsamos el botón Pedir:

El servidor nos mostrará la petición realizada:

Esta claro que este protocolo se creó originalmente para comunicar dispositivos de hardware a través de la red, por lo que si necesitamos realizar llamadas y respuestas entre software de distintas máquinas, lo mejor sería que se comunicasen por TCP y UDP por su cuenta. Esta claro que este protocolo esta diseñado específicamente para administradores de red.

En el siguiente artículo veremos otros pequeños protocolos que abarca esta librería.

Pruebas realizadas en RAD Studio 2007.

Publicidad