How to access/use Indy server/client 's OnReceive and OnSend event ? - c++builder

I use c++ builder XE8, and I am a beginner. I want to use OnReceive and OnSend event of Indy server and client to make it work in non-blocking mode. I have read that Indy server/client works in blocking mode, and to make it work i have to use a separate thread. I also found example but those were in delphi not c++. Can I do this using Intercept/IOHandler, or I have to use separate thread ? Please give a short example code.

I want to use OnReceive and OnSend event of Indy server and client to make it work in non-blocking mode.
Indy uses blocking sockets exclusively. You cannot use them in a non-blocking mode. There are no OnReceive and OnSend events, like there are in the VCL's TClientSocket and TServerSocket components.
I have read that Indy server/client works in blocking mode, and to make it work i have to use a separate thread.
That is true.
Indy servers are multi-threaded. TIdTCPServer has OnConnect, OnDisconnect, and OnExecute events that are triggered in the context of worker threads, one for each connected client. TIdUDPServer has an OnUDPRead event that is triggered in the context of worker threads, one foor each listening port. You need to do your socket I/O in these events. Typically, you would simply perform whatever read/write operations you need and let Indy block the calling thread as needed.
Indy clients are mostly single-threaded, they run in the context of whatever thread they are used in (TIdCmdTCPServer and TIdTelnet being the exception to that rule). So you usually have to create your own thread to manage the socket I/O if you want non-blocking behavior.
Please read the documentation for more details:
Introduction to Indy
I also found example but those were in delphi not c++.
And? The components are the same in both languages. So either translate the code from Pascal to C++, or just use the code as-is (did you know that you can use Delphi code in C++Builder projects? You can).
Can I do this using Intercept/IOHandler
No. An Intercept is meant for manipulating data as it passes to/from the connection (to apply encryption, compression, etc). The IOHandler performs the actual I/O operations, but it has nothing to do with threading.
or I have to use separate thread ?
Yes.
Please give a short example code.
There are plenty of examples readily available if you search around. StackOverflow is not the place to ask for them.

Related

Delphi's TNetHTTPClient descendant supporting http2

I am trying to communicate with Google Cloud Speech via gRPC from a Delphi 10.3.1 Windows client application. For this, the communication needs to be using http2 as protocol, and data needs to be transmitted 2-ways async.
Delphi includes TNetHTTPClient, which is used by TNetHTTPRequest for http communication. Using the debugger, I found that TWinHTTPClient in System.Net.HttpClient.Win.pas is used internally for the communication.
To add http2 support, I inserted 2 lines in TWinHTTPClient.DoExecuteRequest in System.Net.HttpClient.Win.pas, at line 1360:
LOptionValue := 1;//WINHTTP_PROTOCOL_FLAG_HTTP2;
WinHttpSetOption(LRequest.FWRequest, WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL, #LOptionValue, sizeof(LOptionValue));
After adding the above code, the component is using http2, which I verified by calling Google Cloud Speech Sync Request endpoint via gRPC successfully.
However, my approach has two major disadvantages:
It needs Delphi Source Code modification.
It does not support async bidirectional transport of data, for which I think an event a la OnDataReceived that may be triggered without the connection being closed is necessary.
I tried to find a point where I could replace TNetHTTPClient by a modified component TMyNetHTTPClient, but I did not succeed.
So, the question is: how to create a TNetHTTPClient replacement, based on TWinHTTPClient, that supports http2 and implements OnDataReceived event without closing the connection?
It's not based on TNetHTTPClient, but grijjy have open-sourced an HTTP2 Delphi client for Windows and Linux.
You can find it here - https://github.com/grijjy/DelphiScalableClientSockets
A bit late, sorry :)
I don't know how to implement the async bidirectional transport of data. I do know how TWinHTTPClient is constructed. Unfortunately, as you found out, since TWinHTTPClient is hidden in the unit's implementation, you cannot extend it.
You could copy that unit, make the necessary modifications, and use the modified class instead. It's not ideal at all to copy it, since it's a unit of over 2000 lines, but unfortunately there is no way around that.
But how to construct the modified TWinHttpClient, since normally you wouldn't construct a TWinHttpClient directly at all? That's a bit tricky, especially if you want to use other classes (like TNetHttpClient), that construct their own HttpClient internally.
TWinHTTPClient registers itself as a handler for HTTP and HTTPS. The unit itself does that by invoking TUrlSchemas.RegisterURLClientScheme.
You could unregister the TWinHttpClient class, and register your own like so:
TURLSchemes.UnRegisterURLClientScheme('HTTP');
TURLSchemes.UnRegisterURLClientScheme('HTTPS');
TURLSchemes.RegisterURLClientScheme(TYourWinHttpClient, 'HTTP');
TURLSchemes.RegisterURLClientScheme(TYourWinHttpClient, 'HTTPS');
After that, you can call THttpClient.Create, which is actually not a constructor but a class function that will invoke TURLSchemes to get an instance of the registered class.
That is, it finds the class, and calls the CreateInstance class function of that class. CreateInstance is a virtual factory method of TUrlClient, the ultimate base class. Your class should override that method to create and return an instance of itself.
It's a freaky construction. THttpClient is not just the base class for the various platform-specific descendants, but it's also a factory for them.
I happened to bump into this logic (and this question), when I was trying to create a THttpClient descendant for unit-testing purposes and ran into some surprise behavior. I'm not yet sure if it's genius or madness, or both :D
TUrlClient, THttpClient and TWinHttpClient are RTL classes, meant to be instantiated from code.
TNetHTTPClient is a TComponent that you can place on a TForm or TDataModule to configure design time. At runtime, when making requests, it uses THttpClient internally. It should use your modified version if you register it.

Indy10 TCP client deliver reply to sending procedure

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.

C++Builder - Correct way to take action on application startup

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.

Delphi Service to Listen to TCP or UDP

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.

Indy or ICS or ?

Can any one tell me which is more stable? I know each has their own advantages and disadvantages. But which one is better for http, etc?
In my previous application I used indy9 but I wasn't satisfied with it, as I would sometimes get strange errors.
Can anyone recommend one?
I use Indy in a lot of projects. I used both 9 and 10 mainly as HTTP server and proxy. The projects get very intense traffic at times (HTTP). Indy never did let me down. It works very stable.
But I also had some "strange" situations where I had to dig deep to find the underlying problem. I also do not like the way Indy tends to handle a lot of things through exceptions. In general I like the ICS coding style more. But let me go to ICS.
ICS uses non-blocking sockets, while indy uses blocking. While non-blocking is ok and seems to be better at first sight, I found it irritating in a lot of situations. The problem is that the natural flow of the code gets lost because of the callback functions. This makes it harder to write procedural type of libraries. Furthermore I do not like how everything is handled through messages. For me it gets messy real quick when mixed with multithreading. And multithreading is mainstream these days.
So while I like the coding style and quality of the code in ICS, I prefer the simplicity of use and blocking mode of Indy. What you like more is up to you, but both libraries are mature and stable.
These are my two cents.
I also use both Indy and ICS.
Most of the time I prefer Indy because implementing sequential type of protocols with it is very easy (the request runs in it's own thread so you simply Read/Write to the connection, really easy). Using Indy requires solid knowledge of threading and synchronization. Unlike Runner I like how Indy uses Exceptions to handle "exceptional" stuff because it allows me to concentrate on the normal flow of the protocol (I use try-finally blocks to make sure I deallocate resources).
I also used ICS in a application where Indy simply failed: I used it for an application that implements an TCP/IP proxy. Using ICS was simpler because of it's non-blocking nature. I was able to "proxy" TCP/IP protocols that I know nothing about, so I have no idea how bytes would flow from one end to the other. Indy failed in that scenario because in Indy you're ether reading or you're writing, you can't do both at the same time. Using ICS to implement an sequential-type protocol is a bit of pain: you essentially need to use state-machine logic, brake the protocol in small bits, keep flags laying around so you know where you are in the protocol. An big plus: François Piette, the author of ICS, is active and very helpful on a number of forums and mailing list, and is very prompt to help with anything related to ICS.
For me, if I need to do something with TCP/IP, the decision path is very simple: Can it be done with Indy? Then it's Indy. If it can't be done with Indy then it'll be done with ICS!
I've used Indy 9 and 10 for TCP, HTTP and FTP with very few problems. ICS is a good choice, too. It's non blocking, which will change how you use it.
I haven't used it, but I've heard good things about Synapse, which is also blocking.
We test Indy10 IdTCPClient to receive video stream from remote server, it's OK. But when it's receiveing stream, the same time use it send some data to the server, after some minute, the received stream data began lost data bytes. We use sniffer tool to trace this problem, confirmed that IdTCPClient lost some bytes in receiveing stream.
So, we test Indy9.018, the same problem happend but a few times VS. Indy 10.
Remember that Indy is always in beta stage. Sometimes you need to work with night builds.
Which one is better really depends on specific use case, but I was unhappy with indy as an http client and ICS ended up being exactly what I needed it to be, with a lot less random quirks.
Note though that it is non blocking, so it's not just a drop in replacement.
I use Indy 9 for stable, released, production code to over 1 million users, and have never received any strange errors.
I'd say the answer depends on what you want to do with the internet. Indy is fine if you are prepared to get involved with understanding how it works, and is very capable. ICS is a different take on things, and I've used it effectively for many-connection systems. But for day to day "grab a file or send an email" type stuff, where you want to do a basic task, I pretty much always use Clever Components Internet Suite as you just create the component,
set the options, and it works. The suite is quite comprehensive, and gets useful updates.

Resources