Tôi đang cố gắng tạo một bộ ứng dụng khám phá lẫn nhau bằng cách sử dụng UDP và phát tin nhắn. Các ứng dụng sẽ định kỳ gửi một gói UDP cho biết họ là ai và họ có thể làm gì. Ban đầu, chúng tôi chỉ sử dụng để phát sóng tới INADDR_BROADCAST.nhận các gói UDP gửi tới 127.0.0.1 khi sử dụng SO_REUSEADDR
Tất cả các ứng dụng chia sẻ cùng một cổng để nghe (do đó SO_REUSEADDR). Một đối tượng nhân sự kiện được gắn vào socket để chúng ta nhận được thông báo khi chúng ta có thể lấy một gói mới và sử dụng nó trong một vòng lặp WaitFor. Ổ cắm được sử dụng không đồng bộ.
Mở ổ cắm:
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);
gửi ra dữ liệu vào một danh sách cụ thể các địa chỉ:
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;
gói nhận:
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;
Khi chúng tôi gửi đi dữ liệu phát sóng sử dụng INADDR_BROADCAST, địa chỉ phát sóng địa phương (192.168.1.255) hoặc địa chỉ IP cục bộ đều hoạt động tốt. Thời điểm chúng tôi sử dụng 127.0.0.1 để "phát sóng", tiếp nhận là không thường xuyên nhưng thường không hoạt động.
Có ai có manh mối về cách giải quyết vấn đề này không (danh sách địa chỉ có thể thay đổi)? Nếu mọi thứ khác thất bại, tôi sẽ tra cứu tất cả các địa chỉ IP cục bộ và chỉ thay thế 127.0.0.1 bằng địa chỉ đó nhưng điều đó sẽ khiến các vấn đề khi địa chỉ IP thay đổi.
Cập nhật: Khi bạn lần đầu khởi động App1, App1 sẽ nhận gói. Tiếp theo bạn khởi động App2. Bây giờ App1 vẫn sẽ nhận được gói nhưng App2 sẽ không. Nếu bạn dừng App1, App2 sẽ bắt đầu nhận gói. Nếu bạn khởi động App3, App2 sẽ nhận các gói của nó nhưng App3 thì không.
Do đó: chỉ một ứng dụng sẽ nhận các gói khi 127.0.0.1 được sử dụng.
Cũng đặt IPPROTO_IP, IP_MULTICAST_LOOP thành một với setsocketopt không thay đổi bất kỳ thứ gì.
Tôi sẽ xem xét phát đa hướng thay vì phát sóng. Những gì tôi thấy từ ví dụ của bạn là tôi nên xem xét IP_ADD_MEMBERSHIP/IP_MULTICAST_LOOP. Cảm ơn bạn cho ví dụ. –
Sau khi thử mọi thứ, nó đã làm việc để sử dụng multicasting thay vì phát sóng. –