UDPとブロードキャストメッセージを使用して、一連のアプリケーションがお互いを検出できるようにしようとしています。アプリケーションは定期的にUDPパケットを送信し、自分が誰で何ができるかを示します。最初は、INADDR_BROADCASTへのブロードキャストにのみ使用します。
すべてのアプリケーションは、リッスンする同じポートを共有します(したがって、SO_REUSEADDR)。イベントカーネルオブジェクトがソケットにアタッチされているため、新しいパケットをフェッチしてそれをWaitForループで使用できるようになると通知が届きます。ソケットは非同期で使用されます。
ソケットを開く:
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 );
指定されたアドレスのリストにデータを送信します。
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;
パケットの受信:
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;
INADDR_BROADCASTを使用してブロードキャストデータを送信する場合、ローカルブロードキャストアドレス(192.168.1.255)またはローカルIPアドレスはすべて正常に機能します。127.0.0.1を使用して「ブロードキャスト」する瞬間、受信は散発的ですが、通常は機能しません。
誰かがこれを解決する方法の手がかりを持っていますか(アドレスリストは変更可能です)?他のすべてが失敗した場合は、すべてのローカルIPアドレスを検索し、127.0.0.1をそれに置き換えますが、IPアドレスが変更されると問題が残ります。
更新:App1を最初に起動すると、App1はパケットを受信します。次に、App2を起動します。これで、App1は引き続きパケットを受信しますが、App2は受信しません。App1を停止すると、App2はパケットの受信を開始します。App3を起動すると、App2はパケットを受信しますが、App3は受信しません。
したがって、127.0.0.1が使用されている場合、1つのアプリケーションのみがパケットを受信します。
また、IPPROTO_IP、IP_MULTICAST_LOOPをsetsocketoptを使用して1に設定しても、何も変更されません。