I am using indy's http server for a project so i have a few questions:
Does the event OnConnect get's executed even if one connects on a separate thread?
Can i update the vcl from the event OnConnect
If MaxNumberConnections is
set to 0 what does it exactly mean ?
Thanks.
1. Does the event OnConnect get's executed in a separate thread ?
Yes, the event will get fired as the other events do, even if you are running in a separate thread. The question remains to be answered by you is why. The TIdTCPServer already uses multithreading thus it can be used in a main thread context (on a form).
2. Can I update the VCL from the OnConnect event ?
Yes, but you will have to use some GUI synchronization practice, such as Synchronize method or e.g. message posting from the separated worker thread to your main one.
3. If MaxNumberConnections is set to 0 what does it exactly mean ?
Zero value assigned to the MaxConnections means there is no limit of connections at one time.
Related
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.
I am making a client program in Delphi 7 with Indy 10.
It must connect to the server with TIdTCPClient and keep alive the connection for sending and getting commands and replies until the program is closed.
The server can maintain only one constant connection per client to send info-messages.
TIdTCPClient is listening through a reading thread.
QUESTION:
I am sending a request to the server (using WriteLn) from some procedure to get a list of strings, for example. How can I get the answer (reply) for that request in the same procedure, without leaving it? Like using TIdHTTP.
I see 2 solutions:
making the request from one procedure and handle it in other - the code and logic will be more complicated.
for each request in a procedure, create a new TIdTCPClient (Connect, WriteLn, ReadLn, Disconnect, Free) and handle request. But I do not like this solution as it causes large overhead.
Since a reading thread is involved, it does complicate things a little. The reading thread needs to be the one to receive all of the replies and then it can dispatch them to handlers as needed.
Your first solution is fine, if you don't mind breaking up your code. This is the simplest solution, and the best one if the main thread is the one making the requests. You should never block the main thread.
As you mentioned, your second solution is not a very good one.
Another solution would be to create a TEvent for each request, and put each request into a list/queue somewhere. Have the reading thread find and signal the appropriate event when a response is received. The sending procedure can then wait on the event until it is signaled (TThread.Synchronize() works this way, for example). If the procedure is running in the main thread, use MsgWaitForMultipleObjects() to do the wait, so you can still service the main message queue while waiting.
Using C++Builder XE5.
My main form has an Indy blocking socket which I would like to connect to and block on, as soon as the application has started up and the main form shown.
What is the correct way to do this?
In previous versions or C++Builder, OnCreate and AfterConstruction were both unreliable. Normally I put code like this in the main .cpp file, just before Application->Run(), however that is not appropriate here because I am going to block (and rely on the TIdAntifreeze for message processing).
One way I thought of is to define a custom windows message and post that to myself, but I'm wondering if there is a "proper" way.
My main form has an Indy blocking socket which I would like to connect to and block on, as soon as the application has started up and the main form shown.
Do you really need to do blocking I/O in the main UI thread? Blocking operations, such as Indy's socket I/O, should be done in a worker thread instead.
If the main thread needs to block on a socket operation while still processing UI messages, you can use a waitable event object via CreateEvent() with MsgWaitForMultipleObject() in a loop that calls Application->ProcessMessages() only when there are messages to process, breaking the loop when the event is signaled. This is not generally the best option though. An event-driven model, where the worker thread notifies the main thread of activity/results, would be a better choice. You really should never block the main UI thread for anything.
What is the correct way to do this?
I would suggest having the MainForm constructor create a worker thread, and then the thread can manage the socket operations and synchronize with the main UI when needed.
In previous versions or C++Builder, OnCreate and AfterConstruction were both unreliable.
AfterConstruction() is reliable, and always has been. It is only the OnCreate event that was unreliable, and should never be used in C++ in favor of the constructor instead.
Normally I put code like this in the main .cpp file, just before Application->Run(), however that is not appropriate here because I am going to block (and rely on the TIdAntifreeze for message processing).
You really should not rely on TIdAntiFreeze, a worker thread is a better choice.
One way I thought of is to define a custom windows message and post that to myself
That will work. I use that technique myself at times. Just be aware that it is an HWND-based solution, so you need to make sure the HWND you post to is not destroyed/recreated after you post the message and before it is retrieved from the message queue. If you use the MainForm's HWND, post the message in the OnShow event. A better option is to use AllocateHWnd() to create a dedicated HWND for your custom messages.
Reading this question:
Delphi Windows Service Design, I saw that most designer use this code below in the OnExecute of the TService or in the TThread method, in order to keep service alive.
while not Terminated do
begin
// do something
end;
But what if I need (and I do) to create a service to respond (using Indy) to messages sent by the main application in order to send back some authentication data, what do I do with this code, ignore it or put some Sleep() in it?
Indy's TIdTCPServer and TIdUDPServer components are multi-threaded, so you don't really need to use the TService.OnExecute event at all. You could just activate them in the TService.OnStart event and deactivate them in the TService.OnStop event, and then assign handlers to the TIdTCPServer.OnExecute and TIdUDPServer.OnUDPRead events as needed. Both events are already looped for you, so you don't need a while not Terminated loop in them. Just read/process one request as needed, then exit, and wait for the next event to repeat. Let the server handle any exceptions that are raised. And keep in mind that TIdUDPServer has a ThreadedEvent property that is False by default, so you should set it to True inside a service.
I am developing an application in which I must handle some lists (insertion, deletion). The problem is that the list can suffer alteration from a TTimer component and from a TServerSocket.
How can I protect the lists from being altered by the TTimer and the TServerSocket at the same time? Should I use threads?
Timer events are running in the application's main thread. I am not sure about TServerSocket events (may be a configuration option).
Generally: If both accesses are running in the main thread, you do not need a critical section because the other event can only fire when the first event has already finished (unless you call Application.ProcessMessages which you shouldn't anyway). A critical section wouldn't work in this scenario any way because it will only sync separate threads.
If they are running in different threads, you need some kind of synchronization. A critical section is one option, others include Mutexes, spin locks etc.
Try to use this or a variation thereof:
http://www.swissdelphicenter.ch/en/showcode.php?id=2167