Der schöne Günther 316 Posted December 30, 2020 I am running a http server locally. I am connecting to it from the very same process. I am very puzzled by the time it takes. To me, it seems that resolving the name "localhost" takes 2 seconds before it times out and defaults to "127.0.0.1": Time taken for http://127.0.0.1: 42 ms Time taken for http://localhost/: 2008 ms Time taken for http://localhost/: 3 ms This is the full source code: program Project1; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, System.Net.HttpClient, System.Diagnostics, IdContext, IdHTTPServer, IdCustomHTTPServer; type TServerClientTest = class private var client: THTTPClient; server: TIdHttpServer; private procedure handleServer( AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo ); public constructor Create(); destructor Destroy(); override; procedure Test(const url: String); end; constructor TServerClientTest.Create(); begin inherited Create(); server := TIdHTTPServer.Create(nil); server.Bindings.Add().Port := 80; server.OnCommandGet := handleServer; client := THTTPClient.Create(); end; destructor TServerClientTest.Destroy; begin server.Free(); client.Free(); inherited; end; procedure TServerClientTest.handleServer( AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo ); begin AResponseInfo.ContentText := '<html><body><h1>Hello World</h1></body></html>'; AResponseInfo.WriteHeader(); AResponseInfo.WriteContent(); end; procedure TServerClientTest.Test(const url: String); var stopWatch: TStopwatch; begin stopWatch := TStopwatch.StartNew(); try server.Active := True; client.Get(url); finally stopWatch.Stop(); end; WriteLn( String.Format('Time taken for %s: %.0f ms', [url, stopWatch.Elapsed.TotalMilliseconds])); end; var serverClientTest: TServerClientTest; begin serverClientTest := TServerClientTest.Create(); try serverClientTest.Test('http://127.0.0.1'); serverClientTest.Test('http://localhost/'); serverClientTest.Test('http://localhost/'); finally serverClientTest.Destroy(); end; ReadLn; end. Does anybody have an idea why this is? Share this post Link to post
Guest Posted December 30, 2020 (edited) server.Bindings.Add().Port := 80; would be because you would be access by internet search... then the search go and back according with your net speed? ... I suppose!!! Edited December 30, 2020 by Guest Share this post Link to post
aehimself 396 Posted December 30, 2020 Which operating system are we talking about? 2 seconds sounds like the default DNS client timeout. Sometime around Windows 8 (needs clarification, I'm not sure), the following lines appeared in the Windows hosts file: # localhost name resolution is handled within DNS itself. # 127.0.0.1 localhost # ::1 localhost You can try to uncomment these and give an other try. It's possible that your DNS settings needs to be checked / updated. Share this post Link to post
Guest Posted December 30, 2020 (edited) for Localhost it should be in millisseconds.normally < 100ms... say, 10ms try some this article https://docs.microsoft.com/en-us/previous-versions/tn-archive/bb727023(v=technet.10)?redirectedfrom=MSDN Edited December 30, 2020 by Guest Share this post Link to post
Angus Robertson 574 Posted December 30, 2020 (edited) If your PC supports IPv6, using localhost will try both IPv6 and IPv4, so best to have your server listening on both 127.0.0.1 and ::1. I recently changed the ICS TSimpleWebServer to do exactly this, for this reason. You may think you can ignore IPv6, but life is not that simple for developers. Angus Edited December 30, 2020 by Angus Robertson 4 1 Share this post Link to post
Der schöne Günther 316 Posted December 30, 2020 1 hour ago, Angus Robertson said: using localhost will try both IPv6 and IPv4, so best to have your server listening on both 127.0.0.1 and ::1 That did the trick, thank you! Time taken for http://127.0.0.1: 28 ms Time taken for http://localhost/: 6 ms Time taken for http://localhost/: 5 ms I hope I did that binding stuff correctly: constructor TServerClientTest.Create(); var binding: TIdSocketHandle; begin inherited Create(); server := TIdHTTPServer.Create(nil); binding := server.Bindings.Add(); binding.Port := 80; binding.IPVersion := TIdIpVersion.Id_IPv4; binding.IP := '127.0.0.1'; binding := server.Bindings.Add(); binding.Port := 80; binding.IPVersion := TIdIPVersion.Id_IPv6; binding.IP := '::1'; server.OnCommandGet := handleServer; client := THTTPClient.Create(); end; 2 Share this post Link to post
Guest Posted December 30, 2020 WOW! then my tips is not so wrong... about a Internet intervention (maybe the DHCP.. I dont know 😂 Share this post Link to post
Angus Robertson 574 Posted December 31, 2020 If this application is for wider use, you need to make sure IPv6 is enabled on the PC, otherwise the binding will fail. Many people disable IPv6 to quickly solve problems rather than fixing them properly. Angus 2 Share this post Link to post
Der schöne Günther 316 Posted December 31, 2020 Thank you. Do you have a suggestion on how to properly check that? I am only using Indy, no other libraries like ICS. Share this post Link to post
Angus Robertson 574 Posted December 31, 2020 In ICS, there is a function that includes code attempting to open an IPv6 UDP socket, which fails if there are IPv6 addresses, you'd need something similar, if Indy does not have a similar function. s := Ics_socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); Result := s <> INVALID_SOCKET; if Result then begin Ics_closesocket(s); GIPv6Available := 1; end else GIPv6Available := 0; Angus Share this post Link to post
Der schöne Günther 316 Posted December 31, 2020 Adding a ipv6 binding causes Indy to call socket like this: socket(AF_INET6, SOCK_STREAM, 0 {no protocol specified}) which is apparently fine with Windows as it returns a valid socket descriptor, although ipv6 is disabled. Maybe this is just a problem when UDP is used? For me, everything seems fine. It doesn't seem I need to handle the "ipv6 was manually disabled" case. 😎 Share this post Link to post
Rafael Dipold 0 Posted January 18 Enjoying the topic, is there any way to force the connection only via IPv4 in this example? LHTTPClient := THTTPClient.Create; try LHTTPResponse := LHTTPClient.Get(LURL); //Error sending data: 12002.Time limit exceed Result := LHTTPResponse.ContentAsString(TEncoding.UTF8); finally LHTTPClient.Free; end; Because in a few cases, my clients who use my software end up receiving the error message described in the comment, and when I manually disable the IPv6 protocol in the Windows network settings, the software starts working again. =/ I understand that IPv6 must be misconfigured on the router or server on the client's network, however, by forcing the use of IPv4, I would no longer need to waste time with this type of problem that is not related to my software Share this post Link to post
Remy Lebeau 1400 Posted January 18 3 hours ago, Rafael Dipold said: is there any way to force the connection only via IPv4 in this example? If you were using Indy's TIdHTTP, then it would automatically use IPv4 unless the requested URL is bracketed, eg: "http://[HostOrIPv6Address]/", which would force IPv6. For the RTL's THTTPClient, I have no idea how it behaves in regards to IPv4/IPv6. 2 Share this post Link to post
Rafael Dipold 0 Posted January 19 I'll try, but the disadvantage of Indy is that I would have to include the SSL libraries and control the version of that too.. I believe it would be possible to implement this using THTTPClient by activating the option flag WINHTTP_OPTION_IPV6_FAST_FALLBACK https://learn.microsoft.com/en-us/windows/win32/winhttp/option-flags However, I believe that this could only be done by modifying Delphi's RTL by Embarcadero to include such an option... Share this post Link to post