We use TIdSMTPRelay to relay some messages. Sometimes the receiving email server will hang and just keep the connection open and our relayer never times out. Is there a way of giving it e.g. 5 mins to deliver the message and then give up?
TIdSMTPRelay has ConnectTimeout and ReadTimeout properties. Indy does not have a SendTimeout property, so if the hang is occurring during a send rather than a connect/read, the only option would be to manually assign an SO_SNDTIMEO timeout on the underlying socket itself, such as by using the Socket.Binding.SetSocketOption() method in the OnConnect event.
Related
Is there an easy way to get the time it took Indy to connect, and the time it took to receive data, in a TIdHTTP.Get() or TIdHTTP.Put() operation?
EDIT:
I want to get statistics to determine which timeouts are best to use for the ReceiveTimeout and ConnectTimeOut properties.
For timing a connect, you can use the OnStatus(hsConnecting) and OnStatus(hsConnected)/OnConnected events. Note that if a URL involves a hostname (which is the usual case), there is also an OnStatus(hsResolving) event that precedes the OnStatus(hsConnecting) event. However, DNS resolution does not play into ConnectTimeout handling at this time.
For timing the receive, that is a bit trickier, since there are no events for detecting the end of sending a request, or the beginning/ending of reading a response 1. And also that a given HTTP request may involve multiple steps (redirects, authentication, etc), which may also involve multiple disconnects/re-connects since HTTP is a stateless protocol not dependent on a persistent connection, like most other protocols are. So, about the only way I can think of accomplishing this is to attach an Intercept component to the TIdHTTP.Intercept property and then manually parse the HTTP messages as they are being exchanged.
1 Actually, that is not entirely true. There is a TIdHTTP.OnHeadersAvailable event, which is fired after the HTTP response headers have been read, and before the HTTP response body is read, at least. So, if you don't care about the timing of the headers, you can use that event to start timing the receiving of the body data, at least. And then stop the timing when Get()/Post() exits. For each multi-step that requires TIdHTTP to repeat a request, you should get a new OnHeadersAvailable event, which you can use to reset your timer. That way, you end up with the time of the final response only.
However, note that ReceiveTimeout is a per-byte timeout, so an alternative might be to use a custom TStream (or Indy's TIdEventStream) to receive the HTTP response data into, and then you can time the durations between individual writes to that stream by overwriting its Write() method (or using the OnWrite event).
I use Delphi 10.2 Tokyo with Indy (the integrated version).
Scenario:
I do http GET requests (TIdHttp) in threads, and use proxies.
Sometimes, a proxy seems to cause Indy not to timeout, and not to return from a GET.
I also assign the onWork event handler to react to an Abort button and call within this handler the idHttp.Disconnect function. When the GET seems to be frozen, the abort also does not work, possible that in this case the onWork event is not triggered, I have no idea.
The main thread is idle and only create lets say 50 threads, each does a GET via its instance of TIdHttp. Ans sometiumes, as I mentioend, a proxy cause of GET not to return which result then in a "hanging" thread.
My question is: How can I force Indy to abort, from an external thread? Is there anything what can be done via code when the GET refuse to return?
I solved my issues by using a background thread to disconnect sockets and implement a timeout, which seems to work even socket are "frozen" and the onWork is not triggered.
I do this by adding the TIdHttp instances I create to an array, together with the time the instance was created. If the GET return normal, the array entry will be removed. In a background thread, I check if the user clicked Abort, and then loop through the array and call disconnect on each instance. I also check in the same thread if a timeout period was reached, and also call disconnect.
Might not be the perfect solution, but it works for me.
How can I send multiple post requests using TIdHTTP at the same time?
lHTTP1.Post('http://'+cURL+'/build.php?',lParamList, ResponseContent);
lHTTP2.Post('http://'+cURL+'/build.php?',lParamList, ResponseContent);
lHTTP3.Post('http://'+cURL+'/build.php?',lParamList, ResponseContent);
I tried using three threads to do that, but there is a one second delay between every post message.
How can I send all the post messages in the same second?
Since TIdHTTP is a blocking component, using separate threads is the correct approach. The 1s delay on each post could be related to how the OS schedules threads, or it might be related to network delays, or you might be using a version of Indy that has internal delays (for instance, if an HTTP server sends a 3xx response to a POST request, TIdHTTP waits up to 5s to make sure the server sends a proper response body - some buggy servers do not). It is difficult to know where your 1s delay is actually occurring. You will have to debug/profile your project to find out, we can't do that for you.
I'm trying (with a lot of help from this community) to put together my first client/server app.
I am using Indy 10 and Delphi Xe2, but suspect my problem does not lie with those, but rather with how soockets work (wizardy and black arts, if you ask me).
Because I often hit breakpoints of exceptions and step through my code before pressing Alt+F2 to halt, my next runs often hit exception "already connected" and eventually I get "too many connections".
How can I tidy this up?
(also, does anyone have a demo which uses try ... except, ratehr than try ... finally as in the Indy demos?)
"already connected" occurs on the client side when you call Connect() while Connected() still returns true. That usually occurs if you disconnect and leave unread data in the IOHandler.InputBuffer. Try clearing the InputBuffer before reconnecting. This is commonly encountered, so a near-future update to Indy may address that issue.
"too many connections" means that you set the server's MaxConnections property to a positive non-zero value and that many simultaneous clients are already connected to the server when a new client tries to connect. If you do not think that you are making that many simultaneous connections, then it usually means that you are not managing the connections correctly in your server code so disconnected clients get cleaned up correctly. The most common cause of that is putting exception handlers in your code that catch and swallow Indy's internal exceptions to itself. If you do catch exceptions, be sure to re-raise any that derive from EIdException and let the server handle them internally.
My app sends data to a Server using a TidTCPClient. The Server uses a TidTCPServer. All works fine and I am now trying to handle unexpected situations.
When I disconnect the network cable between server and client, and then try to close the client, it waits for a long time, until it finally closes:
TCPClient.IOHandler.InputBuffer.Clear;
TCPClient.Disconnect;
TCPClient.Free;
TCPClient.Free is the place where it waits. This is sometimes 30 seconds, sometimes even longer.
Is there a way to terminate a TCPClient immediately, no matter what it is doing at that moment?
You should be clearing the InputBuffer after calling Disconnect(), not before.
In any case, there is no reason for a socket to cause such a hang when disconnecting/freeing the TIdTCPClient, unless you have messed around with the socket's LINGER options. So I have to suspect your own code is at fault first. Which version of Indy are you using? Do you have any event handlers assigned to the TIdTCPClient? Have you tried stepping through TIdTCPClient's destructor in the debugger to see what is really happening?
It probably waits for a timeout. Look at the properties of the component to lower the timeout value