J'essaye de faire un ensemble d'applications se découvrent en utilisant UDP et en diffusant des messages. Les applications enverront périodiquement un paquet UDP disant qui ils sont et ce qu'ils peuvent faire. Au départ, nous utilisons uniquement pour diffuser à INADDR_BROADCAST.recevoir des paquets UDP envoyer à 127.0.0.1 lors de l'utilisation SO_REUSEADDR
Toutes les applications partagent le même port à écouter (d'où le SO_REUSEADDR). Un objet kernel d'événement est attaché au socket afin que nous soyons avertis quand nous pouvons récupérer un nouveau paquet et l'utiliser dans une boucle WaitFor. Le socket est utilisé async.
Ouverture du connecteur:
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'envoi de données à une liste d'adresses:
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;
Réception de paquets:
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;
Lorsque nous envoyons les données de diffusion à l'aide INADDR_BROADCAST, l'adresse de diffusion locale (192.168.1.255) ou l'adresse IP locale tout fonctionne correctement. Au moment où nous utilisons 127.0.0.1 pour "diffuser", la réception est sporadique mais ne fonctionne généralement pas.
Est-ce que quelqu'un a une idée de comment résoudre ce problème (la liste d'adresses est modifiable)? Si tout le reste échoue, je rechercherai toutes les adresses IP locales et remplacerai simplement 127.0.0.1 par cela, mais cela laisse des problèmes lorsque les adresses IP changent.
Mise à jour: Lorsque vous démarrez App1, App1 reçoit des paquets. Ensuite, vous démarrez App2. Maintenant, App1 recevra toujours des paquets, mais pas App2. Si vous arrêtez App1, App2 commencera à recevoir des paquets. Si vous démarrez App3, App2 recevra ses paquets mais pas App3. Ainsi, une seule application recevra les paquets lorsque 127.0.0.1 est utilisé.
La définition de IPPROTO_IP, IP_MULTICAST_LOOP sur un avec setsocketopt ne change rien.
Je vais regarder en multidiffusion au lieu de diffuser. Ce que je vois de votre exemple est que je devrais regarder dans IP_ADD_MEMBERSHIP/IP_MULTICAST_LOOP. Merci pour l'exemple. –
Après avoir essayé les choses, cela a fonctionné pour utiliser la multidiffusion au lieu de la diffusion. –