Search code examples
delphiudpindy10delphi-10-seattle

UDP in Seattle vs Delphi 7


This piece of code runs fine under Delphi 7:

procedure TForm1.FormCreate(Sender: TObject);
   //var    IdUDPClient1: TIdUDPClient;
   begin
     idudpclient1.host := '127.0.0.1';
     idudpclient1.port := 1234;
     idudpclient1.Binding.Port := 1234;
     idudpclient1.Binding.Bind;
     idudpclient1.Send('Hello');
   end;

Running the exact same code under Delphi 10 Seattle 32 bit windows gives socket runtime error 10022: Invalid argument, and then Could not bind socket, address and port are already in use.

Any ideas?

Best regards Thomas Riedel


Solution

  • In Indy 10, when you access the Binding property, the socket gets created and bound if it is not already. So you are trying to call Bind() on a socket that is already bound.

    The "Invalid argument" error is raised when the underlying socket API bind() fails. Per MSDN's bind() documentation:

    WSAEINVAL
    An invalid argument was supplied.

    This error is returned of the socket s is already bound to an address.

    TIdSocketHandle.Bind() calls TIdSocketHandle.TryBind(), and TryBind() catches the "Invalid argument" error, so you should only be seeing it if you are running your code in the debugger. The "Could not bind socket" error is Indy's own error that TIdSocketHandle.Bind() raises if TryBind() fails.

    You should not be setting Binding.Port directly, or calling Binding.Bind() directly, at all. Use the TIdUDPClient.BoundPort property (and optionally also TIdUDPClient.BoundIP) instead:

    procedure TForm1.FormCreate(Sender: TObject);
    //var    IdUDPClient1: TIdUDPClient;
    begin
      IdUDPClient1.Host := '127.0.0.1';
      IdUDPClient1.Port := 1234;
      //IdUDPClient1.BoundIP := '127.0.0.1';
      IdUDPClient1.BoundPort := 1234;
      IdUDPClient1.Send('Hello');
    end;
    

    When TIdUDPClient allocates its socket, it will call Bind() for you, assigning the BoundPort to the Binding.Port (and BoundIP to Binding.IP).

    The reason your code worked in Delphi 7 is because you were using Indy 9 (or earlier) instead of Indy 10. In those earlier Indy versions, accessing the Binding property only allocated the socket, it did not also bind the socket, thus you were able to bind it manually. That is no longer the case.