Могу ли я использовать IdUDPClient для отправки запроса M-SEARCH?

В моей сети мало устройств uPNP. Я пытаюсь отправить запрос M-SEARCH в сеть и надеюсь получить от него ответы. Вот что я пытаюсь:

var sIP, sOut: string;
    iPort: Word;
    S: TStringBuilder;
begin
  S := TStringBuilder.Create;
  try
    S.Append('M-SEARCH * HTTP/1.1').AppendLine
     .Append('HOST: 239.255.255.250:1900').AppendLine
     .Append('MAN: "ssdp:discover"').AppendLine
     .Append('MX: 10').AppendLine
     .Append('ST: ssdp:all').AppendLine;

    IdUDPClient1.ReceiveTimeout := 3000;
    IdUDPClient1.Broadcast(S.ToString, 1900, '239.255.255.250');
    sOut := IdUDPClient1.ReceiveString(sIP, iPort);
    Memo1.Lines.Add(sIP);
    Memo1.Lines.Add(IntToStr(iPort));
    Memo1.Lines.Add(sOut);
  finally
    S.Free;
  end;
end;

Я ничего не получаю от клиента UDP. Я использую Wireshark для мониторинга сетевого трафика, и с моего хоста не было отправлено ни одного сообщения.

Есть идеи? Спасибо.

Наконец-то я нашел ответ:

uses
  System.SysUtils, IdUDPClient, IdStack;

var S: TStringBuilder;
    U: TIdUDPClient;
    iPeerPort: Word;
    sPeerIP, sResponse: string;
begin
  U := TIdUDPClient.Create(nil);
  S := TStringBuilder.Create;
  try
    S.Append('M-SEARCH * HTTP/1.1').AppendLine
     .Append('HOST: 239.255.255.250:1900').AppendLine
     .Append('MAN: "ssdp:discover"').AppendLine
     .Append('MX: 3').AppendLine
     .Append('ST: ssdp:all').AppendLine
     .AppendLine;

    U.BoundIP := GStack.LocalAddress;
    U.Send('239.255.255.250', 1900, S.ToString);

    U.ReceiveTimeout := 1000;
    repeat
      sResponse := U.ReceiveString(sPeerIP, iPeerPort);
      if iPeerPort <> 0 then begin
        WriteLn(Format('%s:%d', [sPeerIP, iPeerPort]));
        WriteLn(sResponse);
      end;
    until iPeerPort = 0;
    ReadLn;
  finally
    S.Free;
    U.Free;
  end;
end.

person Chau Chee Yang    schedule 06.06.2012    source источник


Ответы (3)


Дважды вызовите AppendLine() в конце построителя строк. Заголовки HTTP-запроса завершаются двумя парами CRLF, но вы добавляете только одну пару, поэтому вы отправляете неполный запрос.

person Remy Lebeau    schedule 06.06.2012
comment
Я добавляю новый AppendLine() в объект stringbuilder, но тоже не получил никакого ответа. Я также не заметил запроса, отправленного с моего хоста, при мониторинге трафика через WireShark. - person Chau Chee Yang; 07.06.2012
comment
Вы уверены, что 239.255.255.250 является правильным широковещательным IP-адресом для вашей локальной сети? Какой локальный IP и подсеть назначены ПК вашего клиента? - person Remy Lebeau; 07.06.2012
comment
Если я вещаю на 239.255.255.255, я вижу трафик, отправленный с моего хоста. Но транслировал на 239.255.255.250, трафика не обнаружено. - person Chau Chee Yang; 07.06.2012
comment
Я не уверен, является ли 239.255.255.250 адресом, который я должен транслировать. Я пытаюсь отправить пакет m-search на номер 239.255.255.250, чтобы получить ответы от доступных устройств uPNP в моей сети. Как это сделать с помощью IdUDPClient? Должен ли я транслировать или отправить? - person Chau Chee Yang; 07.06.2012
comment
Я узнал проблему. Я должен установить BoundIP на IP-адрес моего адаптера. Служба узла устройств uPNP не прослушивает 0.0.0.0. Он прослушивает только IP-адрес адаптера хоста. - person Chau Chee Yang; 07.06.2012

Быстрое и грязное решение с использованием TIdUDPServer (Indy 9).

Поместите компонент TIdUDPServer в форму и с помощью Object Inspector установите привязки к вашему локальному IP-адресу, например. 10.1.0.78:0 установите для BroadcastEnabled и Active значение true. Поместите TMemo и TButton на форму.

Завершите события OnClick и UDPRead следующим образом:

uses IdSocketHandle;
...
procedure TForm1.Button1Click(Sender: TObject);
begin
  IdUDPServer1.Send('239.255.255.250', 1900, 'M-SEARCH * HTTP/1.1' + #13#10 +
     'HOST: 239.255.255.250:1900' + #13#10 +
     'MAN: "ssdp:discover"'+ #13#10 +
     'MX: 3'+ #13#10 +
     'ST: ssdp:all'+ #13#10 +
     #13#10);
end;

procedure TForm1.IdUDPServer1UDPRead(Sender: TObject; AData: TStream; ABinding: TIdSocketHandle);
var 
   data: string;
begin

   setlength(data, Adata.Size - AData.Position); //No fragmentation :)        
   AData.ReadBuffer(data[1], length(data));

   memo1.Lines.Add('Read: ' + inttostr(AData.Position) + ' / ' + inttostr(AData.Size) + ' PeerIP: ' + ABinding.PeerIP);       
   memo1.Lines.Add(data);
end;

Спасайся, беги, и Боб станет твоим дядей.

person Noener    schedule 06.12.2012

Для многоадресного M-SEARCH формат сообщения определен ниже. Значения между * * являются заполнителями для фактических значений.

M-SEARCH * HTTP/1.1
HOST: 239.255.255.250:1900
MAN: "ssdp:discover"
MX: *seconds to delay response*
ST: *search target*
USER-AGENT: *OS/version UPnP/1.1 product/version*

Поэтому вам нужно исправить ReceiveTimeout на

U.ReceiveTimeout := 3000;

Оно должно быть как минимум равно задержке вашего запроса (MX:3) 3 секунды = 3000 миллисекунд.

person Volodymyr Karpus    schedule 26.04.2017