Estoy tratando de hacer que un conjunto de aplicaciones se descubran usando UDP y transmitiendo mensajes. Las aplicaciones envían periódicamente un paquete UDP que dice quiénes son y qué pueden hacer. Inicialmente solo usamos para transmitir a INADDR_BROADCAST.recepción de paquetes UDP enviar a 127.0.0.1 cuando se utiliza SO_REUSEADDR
Todas las aplicaciones comparten el mismo puerto para escuchar (de ahí el SO_REUSEADDR). Un objeto kernel de evento se adjunta al socket para que nos notifiquen cuándo podemos obtener un nuevo paquete y usarlo en un bucle WaitFor. El socket se usa como sincronización.
de abrir el aparato:
FBroadcastSocket := socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if FBroadcastSocket = INVALID_SOCKET then Exit;
i := 1;
setsockopt(FBroadcastSocket, SOL_SOCKET, SO_REUSEADDR, Pointer(@i), sizeof(i));
i := 1;
setsockopt(FBroadcastSocket, SOL_SOCKET, SO_BROADCAST, Pointer(@i), sizeof(i));
System.FillChar(A, sizeof(A), 0);
A.sin_family := AF_INET;
A.sin_port := htons(FBroadcastPort);
A.sin_addr.S_addr := INADDR_ANY;
if bind(FBroadcastSocket, A, sizeof(A)) = SOCKET_ERROR then begin
CloseBroadcastSocket();
Exit;
end;
WSAEventSelect(FBroadcastSocket, FBroadcastEvent, FD_READ);
El envío de datos a una lista específica de direcciones:
for i := 0 to High(FBroadcastAddr) do begin
if sendto(FBroadcastSocket, FBroadcastData[ 0 ], Length(FBroadcastData), 0, FBroadcastAddr[ i ], sizeof(FBroadcastAddr[ i ])) < 0 then begin
TLogging.Error(C_S505, [ GetWSAError() ]);
end;
end;
Recibiendo paquetes:
procedure TSocketHandler.DoRecieveBroadcast();
var
RemoteAddr: TSockAddrIn;
i, N: Integer;
NetworkEvents: WSANETWORKEVENTS;
Buffer: TByteDynArray;
begin
// Sanity check.
FillChar(NetworkEvents, sizeof(NetworkEvents), 0);
WSAEnumNetworkEvents(FBroadcastSocket, 0, @NetworkEvents);
if NetworkEvents.ErrorCode[ FD_READ_BIT ] <> 0 then Exit;
// Recieve the broadcast buffer
i := sizeof(RemoteAddr);
SetLength(Buffer, MaxUDPBufferSize);
N := recvfrom(FBroadcastSocket, Buffer[ 0 ], Length(Buffer), 0, RemoteAddr, i);
if N <= 0 then begin
N := WSAGetLastError();
if N = WSAEWOULDBLOCK then Exit;
if N = WSAEINTR then Exit;
TLogging.Error(C_S504, [ GetWSAError() ]);
Exit;
end;
DoProcessBroadcastBuffer(Buffer, N, inet_ntoa(RemoteAddr.sin_addr));
end;
Cuando enviamos los datos de difusión que utilizan INADDR_BROADCAST, la dirección de difusión local (192.168.1.255) o la dirección IP local todo funciona bien. En el momento en que usamos 127.0.0.1 para "transmitir" a, la recepción es esporádica pero generalmente no funciona.
¿Alguien tiene idea de cómo resolver esto (la lista de direcciones es cambiante)? Si todo lo demás falla, buscaré todas las direcciones IP locales y simplemente reemplazaré 127.0.0.1 con eso, pero eso deja problemas cuando cambian las direcciones IP.
Actualización: Al empezar App1, App1 recibirá los paquetes. Luego, comienza la aplicación 2. Ahora App1 aún recibirá paquetes, pero App2 no lo hará. Si detiene la aplicación 1, App2 comenzará a recibir paquetes. Si inicia App3, App2 recibirá sus paquetes, pero App3 no lo hará.
Así: sólo una aplicación recibirá los paquetes cuando se utiliza 127.0.0.1.
también establecer IPPROTO_IP, IP_MULTICAST_LOOP a uno con setsocketopt no cambia nada.
Investigaré la multidifusión en lugar de la transmisión. Lo que veo en su ejemplo es que debería consultar IP_ADD_MEMBERSHIP/IP_MULTICAST_LOOP. Gracias por el ejemplo. –
Después de probar cosas, funcionó usar multicasting en lugar de broadcasting. –