Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум на Исходниках.RU > C/C++: Сетевое программирование > Broadcast рассылка через UDP - как узнать, что мы получили свое же сообщение


Автор: Lun2 25.07.22, 18:33
Добрый вечер!
Как можно узнать, что в результате рассылки UDP broadcast программа получила свое же сообщение ?

Дело в том, что при рассылке всем рассылающий получает свое же сообщение в том числе.

Можно генерировать некоторый случайный ключ при отправке, запоминать его, а при приеме - сравнивать с ним, если совпали, то получили свое же. Интересует кроме этого варианта.

При приеме пакета UDP можно узнать адрес отправителя и сравнить свой адрес с ним, но дело в том, что чтобы узнать свой адрес, необходимо (если я правильно понял) перебирать сетевые адаптеры, т.к. их может быть несколько. Получается уже не очень просто.

Опять-таки, как я понимаю, не перебирать их не получится, т.к. рассылающий не указывает, с какого адаптера делается broadcast-рассылка.

Подскажите, пожалуйста, какой самый простой способ решить эту задачу ?

Автор: Gonarh 26.07.22, 05:15
Цитата Lun2 @
Дело в том, что при рассылке всем рассылающий получает свое же сообщение в том числе.

Вот простейший бродкастер юдп на паскале
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    unit Unit1;
     
    interface
     
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, WinSock, StdCtrls;
     
    const
      WM_ASYNC = WM_USER + 1;
     
    type
      TForm1 = class(TForm)
        Button1: TButton;
        Button2: TButton;
        procedure Button1Click(Sender: TObject);
        procedure Button2Click(Sender: TObject);
      private
        { Private declarations }
      public
        FHandle: HWND;
        procedure SockWND(var AMsg: TMessage); message WM_ASYNC;
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.dfm}
     
    procedure TForm1.Button1Click(Sender: TObject);
    var
      FWSAData: TWSAData;
      FSockAddr: TSockAddrIn;
      FSocket: HWND;
      Option: Boolean;
      Data: String;
    begin
      WSAStartup($0101, FWSAData);
      FSocket := socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
      with FSockAddr do begin
        sin_addr.S_addr := inet_addr('Х.Х.Х.166');
        Option := True;
        SetSockOpt(FSocket, SOL_SOCKET, SO_BROADCAST, PChar(@Option), SizeOf(Option));
        sin_port := htons(6767);
        sin_family := AF_INET;
      end;
      bind(FSocket, FSockAddr, SizeOf(FSockAddr));
      WSAAsyncSelect(FSocket, AllocateHWnd(SockWND), WM_ASYNC, FD_READ);
    end;
     
     
    procedure TForm1.SockWND(var AMsg: TMessage);
    var
        Buffer: array [0..8191] of Char;
        Size: Integer;
        SockAddr: TSockAddrIn;
    begin
        with AMsg do
          case Msg of
              WM_ASYNC: begin
                  case WSAGetSelectEvent(LParam) of
                    FD_READ:
                    begin
                      FillChar(Buffer, 8192, #0);
                      Size := SizeOf(SockAddr);
                      recvfrom(WParam, Buffer[0], 8192, 0, SockAddr, Size);
                      Caption := StrPas(@Buffer);
                      DeallocateHWnd(FHandle);
                      closesocket(WParam);
                      WSACleanup;
                    end;
              end;
          end
            else DefWindowProc(FHandle, Msg, WParam, LParam);
          end;
    end;
     
    procedure TForm1.Button2Click(Sender: TObject);
    var
      FWSAData: TWSAData;
      FSockAddr: TSockAddrIn;
      FSocket: HWND;
      Option: Boolean;
      Data: String;
    begin
      WSAStartup($0101, FWSAData);
      FSocket := socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
      with FSockAddr do begin
        sin_addr.S_addr := INADDR_BROADCAST;
        Option := True;
        SetSockOpt(FSocket, SOL_SOCKET, SO_BROADCAST, PChar(@Option), SizeOf(Option));
        sin_port := htons(6767); // Это порт для броадкаста
        sin_family := AF_INET;
      end;
      Data := 'My first broadcast message!!!';
      SendTo(FSocket, Data[1], Length(Data), 0, FSockAddr, SizeOf(FSockAddr));
      closesocket(FSocket);
      WSACleanup;
    end;
     
    end.

Батон1 - листит юдп порт 6767
Батон2 - срёт броадкастом юдп на порт 6767
У мну ничего не прилетает при броадкасте
Либо у тебя петля в сети, либо ты что-то либо делаешь не так. Показывай код.

Автор: ЫукпШ 26.07.22, 11:17
Цитата Lun2 @
При приеме пакета UDP можно узнать адрес отправителя и сравнить свой адрес с ним, но дело в том, что чтобы узнать свой адрес, необходимо (если я правильно понял) перебирать сетевые адаптеры,

Lun2, приём UDP-пакета производится функцией "RecvFrom".
ссылка
В параметре "sockaddr *from" будет информация о компьютере ("IP" и "PORT") с которого прислан пакет.
Используя эту информацию UDP-сервер отвечает на запросы UDP-клиентов.

Автор: Lun2 27.07.22, 18:34
Gonarh, про петлю - честно говоря, не знаю как ее делать.
Сеть = роутер + 2 компа к нему, никаких доп. настроек.
Broadcast - через sendto() на адрес "255.255.255.255".
Почему я не должен получать свое ?
Это же рассылка ВСЕМ, в числе которых и я :)

Добавлено
ЫукпШ, вопрос касался определение не отправившего, а того, что это мое же сообщение, т.е. я прислал сам себе через broadcast...
Ну, насколько я понял, самое простое все же - включить в сообщение какой-то я отслеживать - если получил его, то значит от себя...

Автор: ЫукпШ 27.07.22, 18:48
Цитата Lun2 @
ЫукпШ, вопрос касался определение не отправившего, а того, что это мое же сообщение, т.е. я прислал сам себе через broadcast...

Ещё разок:
В результате работы RecvFrom будет получена структура sockaddr.
Где будет информация, кто послал пакет.
Просто попробуй посмотреть, что там.
Какой там будет ip, например.
---
Никто не запрещает посылать информацию самому себе.

Автор: Oleg2004 27.07.22, 21:00
ЫукпШ все описал точно. В структуре sockaddr должен быть адрес самого себя :yes:

Автор: Gonarh 29.07.22, 04:18
Цитата Lun2 @
Почему я не должен получать свое ?

Потому что ты не знаешь как работает сетевое оборудование. Изучи как работают коммутаторы, фрейм с дст броадкаст улетит во все порты, кроме того откуда прилетел. Если нет петли, разумеется.
Цитата Lun2 @
Это же рассылка ВСЕМ, в числе которых и я :)

Нет, это рассылка всем, КРОМЕ тебя.
Добавлено
Цитата ЫукпШ @
Ещё разок:
В результате работы RecvFrom будет получена структура sockaddr.
Где будет информация, кто послал пакет.
Просто попробуй посмотреть, что там.
Какой там будет ip, например.

Это не показатель, там м.б. src ip 0.0.0.0, тот же дхцп дисковер например.

Powered by Invision Power Board (https://www.invisionboard.com)
© Invision Power Services (https://www.invisionpower.com)