Search code examples
delphisocketsindy10

Delphi XE3 - Does Reuse socket rsTrue get overridden by system in any case?


Recently I made some very small, very light app that uses two UDP client and two UDP Server components. Apart from several functions, it has basically nothing else in it. I was stuck for a while with "Cannot bind socket. Address and port already in use", but somehow solved that with changing the ports, using rsTrue property on Reuse Socket, but somehow, several users still got that error when they try to run the connection from the app.

The server and client has to use same port and same address, as the UDPClient needs to have BoundPort the same as UDPServer's binding port. That's because the responses are being sent to the same port the request came from. This was causing the primary error, which was solved with rsTrue property.

Now I wonder, is there any chance that system overrides this settings by something, I'm not familiar with? Because on 12 computers I have tested so far, it worked fine (on one I had to kill Bonjour service as it was using the exact port that I needed, but other than that...)

What could be causing errors otherwise?

These are settings which are being called on Connect button click:

Server.Binding.IP:=Interface.Text;
Server.Binding.Port:=StrToInt(Port.Text);
Server.DefaultPort:=StrToInt(Port.Text);

Client.Host:= DeviceIP.Text;
Client.Port:= 10023;
Client.BoundIP:= Interface.Text;
Client.BoundPort:= StrToInt(Port.Text);

LocalServer.Binding.IP:= '127.0.0.5';
LocalServer.Binding.Port:= 10023;
LocalServer.DefaultPort:= 10023;

LocalClient.BoundIP:= '127.0.0.1';
LocalClient.BoundPort:= 10024;
LocalClient.Host:= '127.0.0.1';
LocalClient.Port:= 10023;

try Client.Active:=True; finally end;
try Server.Active:=True; finally end;
try LocalClient.Active:=True; finally end;
try LocalServer.Active:=True; finally end;

Where Port is the TEdit field for user to enter port, DeviceIP the device's IP, and Interface the local network interface IP that he will use.

The only hardcoded thing that doesn't really need to be hardcoded is LocalClient.BoundPort:=10024, it's just to make GUI as light as possible. But changing this doesn't help either.

The app is kind of a proxy server between the original App on PC, and the device on network.

The 10023 must be set as is, since the device only listens on that port, and the original app only sends to that port!

Any help would be appreciated.


Solution

  • You do not need to use separate TIdUDPClient and TIdUDPServer on the same port. You can use TIdUDPServer by itself and let it handle both sending and receiving. No need to use a separate TIdUDPClient at all.

    Also, you are not using the Binding property correctly. When you read a server's Binding property for the first time, the socket is bound using the settings from the server's Bindings collection. Your assignments to Binding.IP and Binding.Port are then ignored. You need to configure the server's Bindings collection first, then use the server's Binding property only for sending (the server will handle the reading for you).

    Try this:

    Server.Active := False;
    Server.Bindings.Clear;
    Server.DefaultPort := StrToInt(Port.Text);
    Server.Bindings.Add.IP := Interface.Text;
    Server.Active := True;
    ...
    Server.Binding.Send(DeviceIP.Text, 10023, data here);
    

    Replies will arrive in the server's OnUDPRead event.

    BTW, since you are writing a proxy, have a look at the TIdMappedPortUDP component.