El siguiente ejemplo muestra como recibir mensajes a través de la red usando el protocolo UDP. Su funcionamiento es muy simple, una vez que se ejecuta se mantiene a la espera de recibir un paquete UDP por alguno de los puertos en los que escucha. Cuando recibe un mensaje lo muestra por pantalla, tanto en hexadecimal como en forma de texto.
El código es el siguiente (es una aplicación de consola):
program udp; {$APPTYPE CONSOLE} uses Windows, SysUtils, Winsock; const START_PORT = 5000; END_PORT = 5005; BUFFER_SIZE = 64*1024; // 64 Kb var Terminar: Boolean; WSAData: TWSAData; function Min(i,j: Integer): Integer; begin if i < j then Result:= i else Result:= j; end; // Muestra el mensage en hexadecimal y como texto procedure WriteHex(Buffer: PAnsiChar; Count: Integer); var i,j: Integer; begin j:= 0; while Count > 0 do begin Write(IntToHex(j,8) + ':' + #32#32); for i:= 0 to Min(Count,8) - 1 do Write(IntToHex(Byte(Buffer[i]),2) + #32); Write(#32); for i:= 8 to Min(Count,16) - 1 do Write(IntToHex(Byte(Buffer[i]),2) + #32); for i:= Min(Count,16) to 15 do Write(#32#32#32); Write(#32 + '|'); for i:= 0 to Min(Count,16) - 1 do if Char(Buffer[i]) in ['A'..'Z','a'..'z','0'..'9'] then Write(Buffer[i]) else Write('.'); Writeln('|'); Dec(Count,16); inc(Buffer,16); inc(j,16); end; end; procedure Loop; var i,j: Integer; b: Boolean; Addr: TSockaddr; AddrSize: Integer; FDSet: TFDSet; TimeVal: TTimeVal; Buffer: PAnsiChar; Sockets: array[START_PORT..END_PORT] OF TSocket; begin // Si el puerto de inicio es mayor que el final terminamos if START_PORT > END_PORT then Exit; b:= FALSE; // Creamos un socket por cada puerto for i:= START_PORT to END_PORT do begin Sockets[i]:= Winsock.Socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); if Sockets[i] <> INVALID_SOCKET then begin with Addr do begin sin_family:= AF_INET; sin_port:= htons(i); sin_addr.s_addr:= Inet_Addr(PChar('0.0.0.0')); end; // Ponemos cada socket a escuhar en el puerto correspondiente if Bind(Sockets[i], Addr, SizeOf(Addr)) = SOCKET_ERROR then begin // Si no podemos cerramos el socket CloseSocket(Sockets[i]); Sockets[i]:= INVALID_SOCKET; end else b:= TRUE; end; end; // Si no pudimos poner a la escucha ningun socket terminamos if not b then Exit; // Reservamos espacio para almacenar los mensajes GetMem(Buffer,BUFFER_SIZE); try // Mientras no pulsamos "Ctrl+C" while not Terminar do begin // Para cada socket for i:= START_PORT to END_PORT do if Sockets[i] <> INVALID_SOCKET then begin TimeVal.tv_sec:= 0; TimeVal.tv_usec:= 500; FD_ZERO(FDSet); FD_SET(Sockets[i], FDSet); // Comprobamos si ha recibido algun mensaje if Select(0, @FDSet, nil, nil, @TimeVal) > 0 then begin AddrSize:= Sizeof(Addr); FillChar(Buffer^,BUFFER_SIZE,#0); // Copiamos el mensaje en el buffer j:= Recvfrom(Sockets[i],Buffer^,BUFFER_SIZE,0,sockaddr_in(Addr),AddrSize); if j <> SOCKET_ERROR then begin // Imprimimos el mensaje Writeln('Puerto: ' + IntToStr(i) + ' IP: ' + inet_ntoa(Addr.sin_addr)); writeln; WriteHex(Buffer,j); Writeln; Writeln; end; end; end; Sleep(10); end; finally FreeMem(Buffer); end; // Cerramos cada uno de los socket for i:= START_PORT to END_PORT do begin if Sockets[i] <> INVALID_SOCKET then begin CloseSocket(Sockets[i]); end; end; end; // Esta rutina maneja la señal "Ctrl+C" function HandlerRoutine(dwCtrlType: DWORD): BOOL; stdcall; begin Result:= TRUE; case dwCtrlType of CTRL_C_EVENT: Terminar:= TRUE; CTRL_CLOSE_EVENT: Terminar:= TRUE; CTRL_LOGOFF_EVENT: Terminar:= TRUE; CTRL_SHUTDOWN_EVENT: Terminar:= TRUE; else Result:= FALSE; end; end; begin Terminar:= FALSE; if SetConsoleCtrlHandler(@HandlerRoutine,TRUE) then begin Writeln('Pulsa Ctrl+C para salir ...'); Writeln; FillChar(WSAData,SizeOf(WSAData),0); if WSAStartup(MAKEWORD(1, 1), WSADATA) = 0 then try Loop; finally WSACleanup(); end; end; Writeln; Writeln('Adios!'); end.
Para probarlo podemos usar cualquier porgrama que permita enviar paquetes UDP.
Yo recomiendo ncat
ncat -u localhost 5001
Si usando el programa anterior enviamos un mensaje con la palabra "PRUEBA" repetida varias veces, obtenemos lo siguiente por pantalla:
Pulsa Ctrl+C para salir ... Puerto: 5001 IP: 127.0.0.1 00000000: 50 52 55 45 42 41 20 50 52 55 45 42 41 20 50 52 |PRUEBA.PRUEBA.PR| 00000010: 55 45 42 41 20 50 52 55 45 42 41 20 50 52 55 45 |UEBA.PRUEBA.PRUE| 00000020: 42 41 20 50 52 55 45 42 41 20 50 52 55 45 42 41 |BA.PRUEBA.PRUEBA| 00000030: 20 50 52 55 45 42 41 20 50 52 55 45 42 41 20 50 |.PRUEBA.PRUEBA.P| 00000040: 52 55 45 42 41 20 50 52 55 45 42 41 20 50 52 55 |RUEBA.PRUEBA.PRU| 00000050: 45 42 41 20 50 52 55 45 42 41 20 50 52 55 45 42 |EBA.PRUEBA.PRUEB| 00000060: 41 20 50 52 55 45 42 41 20 50 52 55 45 42 41 0A |A.PRUEBA.PRUEBA.|
Enlaces de interés:
http://es.wikipedia.org/wiki/User_Datagram_Protocol
http://nmap.org/ncat/