Sto tentando di far scoprire una serie di applicazioni utilizzando UDP e trasmettendo messaggi. Le applicazioni inviano periodicamente un pacchetto UDP che dice chi sono e cosa possono fare. Inizialmente usiamo solo per trasmettere a INADDR_BROADCAST.ricezione di pacchetti UDP inviati a 127.0.0.1 quando si utilizza SO_REUSEADDR
Tutte le applicazioni condividono la stessa porta da ascoltare (quindi SO_REUSEADDR). Un oggetto del kernel di eventi è collegato al socket, quindi riceviamo una notifica quando possiamo recuperare un nuovo pacchetto e usarlo in un ciclo WaitFor. Il socket è usato async.
Apertura della presa:
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);
L'invio di dati a un elenco specifico di indirizzi:
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;
Ricezione pacchetti:
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;
Quando inviamo i dati trasmessi utilizzando INADDR_BROADCAST, l'indirizzo di broadcast locale (192.168.1.255) o l'indirizzo IP locale, tutto funziona correttamente. Nel momento in cui usiamo 127.0.0.1 per "trasmettere" a, la ricezione è sporadica ma generalmente non funziona.
Qualcuno ha la più pallida idea di come risolvere questo problema (l'elenco degli indirizzi è modificabile)? Se tutto il resto fallisce, cercherò tutti gli indirizzi IP locali e sostituirò 127.0.0.1 con quello, ma questo non risolve il problema quando cambiano gli indirizzi IP.
Aggiornamento: Quando si avvia App1 per la prima volta, App1 riceve i pacchetti. Quindi si avvia App2. Ora App1 continuerà a ricevere i pacchetti, ma App2 no. Se si interrompe App1, App2 inizierà a ricevere pacchetti. Se si avvia App3, App2 riceverà i suoi pacchetti ma App3 no.
Così: solo una applicazione riceverà i pacchetti quando viene utilizzato 127.0.0.1.
Anche l'impostazione IPPROTO_IP, IP_MULTICAST_LOOP su uno con setsocketopt non cambia nulla.
Guarderò in multicast invece di trasmissione. Quello che vedo dal tuo esempio è che dovrei esaminare IP_ADD_MEMBERSHIP/IP_MULTICAST_LOOP. Grazie per l'esempio. –
Dopo aver provato, ha funzionato per utilizzare il multicasting anziché la trasmissione. –