我正在尝试使用UDP和广播消息使一组应用程序相互发现。这些应用程序将定期发送UDP数据包,说明它们是谁以及它们能够做什么。最初,我们只会广播到INADDR_BROADCAST。
所有应用程序都共享监听同一个端口(因此使用了SO_REUSEADDR)。将事件内核对象附加到套接字上,以便在可以获取新数据包时得到通知并在WaitFor循环中使用该数据包。套接字是异步使用的。
打开套接字:
将数据发送到指定地址列表:
当我们使用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时接收数据包。
另外,使用setsocketopt设置IPPROTO_IP、IP_MULTICAST_LOOP为1也没有改变任何内容。
所有应用程序都共享监听同一个端口(因此使用了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时接收数据包。
另外,使用setsocketopt设置IPPROTO_IP、IP_MULTICAST_LOOP为1也没有改变任何内容。