Reading data with TIdUDPServer

2019-04-02 17:39发布

问题:

I would like to read data from an electronic device that sends data to my PC by UDP. I have programmed a UDP server in Delphi. An exception occurs in class EIdSocketError (Failure #10049). Here is my code:

procedure TForm1.Button1Click(Sender: TObject);
begin
   IdUDPServer1.Bindings.add.IP := '192.168.1.1';  //Electronic device ip
   IdUDPServer1.Bindings.add.Port:= 49152;         //Electronic device port   
   IdUDPServer1.OnUDPRead:= UDPRead;
   IdUDPServer1.Active:=True;

end;

procedure TForm1.UDPRead (Sender: TObject; AData: TStream; ABinding: TIdSocketHandle);
var
   bytes_received: integer;
begin
   bytes_received:=AData.size;
end;

What am I doing wrong?

Thanks in advance

回答1:

As Keith Miller stated, you are misusing the Bindings property. You are adding 2 bindings to the server - one for 192.168.1.1 on port 0 and another for 0.0.0.0 on port 49152. You need to call Bindings.Add() only once for each IP/Port pair you want to bind to, eg:

var
  Binding: TIdSocketHandle

Binding := IdUDPServer1.Bindings.Add;
Binding.IP := ...;
Binding.Port := ...;

Or:

with IdUDPServer1.Bindings.Add do
begin
  IP := ...;
  Port := ...;
end;

If you set the DefaultPort property ahead of time, then you can simplify the above to this:

IdUDPServer1.DefaultPort := ...;
IdUDPServer1.Bindings.Add.IP := ...;

With that said, socket error 10049 is WSAEADDRNOTAVAIL, which means you are using the wrong IP address in the first place. You need to specify an IP that belongs to the PC that TIdUDPServer is running on - the IP that the device will be sending UDP packets to. You can either bind to the single wildcard IP 0.0.0.0 (or just a blank string ''), which tells TIdUDPServer to bind to all available local IPs:

IdUDPServer1.DefaultPort := ...;
IdUDPServer1.Bindings.Add.IP := ''; // or: '0.0.0.0' 

Or you can use Indy's GStack.LocalAddresses property to determine the locally available IPs and create separate Bindings for them individually as needed.

IdUDPServer1.Bindings.Clear;
IdUDPServer1.DefaultPort := ...;

with GStack.LocalAddresses do
begin
  for I := 0 to Count-1 do
    IdUDPServer1.Bindings.Add.IP := Strings[I];
end;

Update: if you bind the server to port 0 to let the OS pick a port, you can discover what port was selected by looking at the TIdSocketHandle.Port property after the server was activated:

var
  Binding: TIdSocketHandle
  ListeningPort: TIdPort;

IdUDPServer1.Bindings.Clear;

Binding := IdUDPServer1.Bindings.Add;
Binding.IP := ...;
Binding.Port := 0;
{
or: 
IdUDPServer1.DefaultPort := 0;
Binding := IdUDPServer1.Bindings.Add;
Binding.IP := ...;
}

IdUDPServer1.Active := True;

ListeningPort := Binding.Port;