Command via TCP then via COM and callbacks

Hi guys. Hopefully I’ll be able to explain this situation :slightly_smiling_face:

So. I have one PC with my APP that will serve as a server for some clients in the LAN. When this server (my app) will receive some request from some client, it will do a call to some dll (via COM instance etc) and this dll will give back some result, after which the server will hand back the results to the client who called it. The call to dll is synchronous - server issues a call and waits for the result (few seconds).

Now idea is this: I use nettalk’s NetWholePackets to issue a call from client to server and back.
So the flow:

  1. Client sends tcp request to server.
  2. Server (nettalk procedure) gets the request, checks the local queue if this client has connected before. If yes, returns just “BUSY”. Done. If not, it adds this client to the queue.
  3. After adding the client to the queue, it calls the “DLLprocedure” (passing params) which does the toDLL call.
  4. DLLProcedure waits for dll results and sends them back to nettalk procedure.
  5. Nettalk procedure, based on the local queue, returns results to the client and deletes the record in the queue.

Now the issue about sync and threads etc. If there was one client, it would be simple - call after call after call and back. But it’s not. So while server is waiting for dll data, some other client might wanna send a new request etc. So I need to keep things between clients and server in sort of async.

So, the idea: Server runs the nettalk procedure (netWholePacket class) on it’s own thread, waiting for requests. When request happens, it has to START the “DLLprocedure” because this one can take time and I must not block the nettalk procedure in processing. But if I do that, then the “DLLProcedure” must do some callback when it’s done. And the call back should actually be to the nettalk procedure, where I keep my queue with “busy” clients list, because nettalk proc needs to return data to the right client.

So I thought ok: request from client comes in, I check the queue, add a record to it with new guid. I START the dllproc passing guid and original request. dllproc starts, calls dll, gets back some data.
Now I’m stuck. How do I send back dll-data+original guid to the nettalk proc which started dll-proc? I need to get back so I can check my queue for guid and send that dll-data back to the right client (and delete the record in the queue)?

AFAIK START’ed procedures cannot return anything. I cannot use NOTIFY back because my GUID and DLL-DATA are both STRINGs.

Did I go in the right way for this? Am I thinking ok trying to keep my nettalk “server” proc free of some calls that would make it stuck, even for a short while? I’m thinking it’s a good idea to START that dll-proc for every client request, make it run in it’s own thread, initiating COM and all that stuff. You know, to keep things thread-safe sort of.

Geez, I hope this makes sense, appreciate the help.

Bostjan

I guess one way would be to forget about callback and just fill the GLOBAL QUEUE with the result and pull data from that queue, based on notification (sort of “soft” callback I’d say). But that means different threads would work with this queue (adding, deleting records) and that’s probably pretty good recipe for a GPF or something…

it look like an interesting program. I would organize it using a task for attending the request, putting it in a queue, starting a task to fulfill the request and wait for a signal to fetch the answer.
Another task for each request, putting the answers in the same queue, and signaling the end of the consult.
Of course, you have to control the acces to the queue.

I’m thinking of a simple NetTalk API server.

Authenticate the local clients based on LAN IP address, machine name, etc.

Return results as JSON,XML, or whatever you need.

Don’t overthink it.

1 Like

I see Don beat me to it a bit, but basically what you are describing is the architecture of the WebServer class. In other words you are about to re-do a huge amount of work that already exists. So, the short version of my answer is;

Make an NetWebServer, API Server, with a bunch of NetWebServiceMethods. Then your client can talk to it from anywhere. It will be using industry standard approaches, will scale well, it will be secure, and can be called from any language.

On the other hand, in case you are curious and you have a lot of time to kill, I’ll explain how it works;

a) The WebServer procedure is listening on a port. When a request arrives it is parsed sufficiently to know that the whole request has arrived. TCP can split packets so you need a way to know this (which yes, the WholePackets class can help with.) Once it has a whole request it creates a block of memory containing the request, a pointer to the server object, and some other stuff, and STARTs a new thread, passing this parameter there.

b) The WebHandler is the object on the new thread. It received the raw request, parses it out, and performs whatever it is asking for. Since it has a pointer to the parent server object it is able to make calls into that object (which requires a lot of care with regard to thread-safety, using Critical Sections and so on.) These are the “callbacks” you are thinking of.

Because the web server makes use of the HTTP protocol there’s a header in each request and response. This tells both ends things they need to know, like the format of the data and so on. If you did a low-level raw implementation yourself you could probably ignore most of this because you “know” the parameters you are working in.

Still, I mention all this for information only - I don’t recommend you waste time coding all this. It’s somewhat complex to get working, and inevitable will grow over time. I’d just make use of what’s already provided for you.

2 Likes

Ha! This actually makes a good proposition.

I think I’ve been sort of avoiding WebServer becuase in my book it’s considered somewhat “thick”, I mean like an overkill to have some requests served (also with the distribution of the whole web folder etc). You know, when you say “WebServer”, my mind goes to servers like Apache, Nginx so I’m like “I’m not setting up whole web server just to respond to few simple calls”. I need to readjust my thinking, I’d say. Setting up “whole web server” will definitely take less time than do everything like I was planning to. That makes my plan an “overkill” actually :slight_smile:

So, just one question, Bruce: when the webhandler will be doing some dll calls which will block it until it gets the response, it does not really influence anything else, since it’s on its own thread, right?

Cheers

Basically, sort of, yes.

More than likely, if the server is processing a job that may take a few seconds, it may use multiple threads to get it done. It can serve the response in “chunks.”

The NetTalk web server is highly optimized for what you’re wanting to do.

1 Like

I think it depends.

If a process is listening to a port, ie BINDed to a port, no other process can listen on that port, so changes have been made to the OS in Windows and Linux over the years to allow “port sharing”.

Traditionally, TCP listeners didnt share a port so you could only have one listener on a TCP port.

I havent used Nettalk since version 4 or 5 I think, so I dont know if Nettalk has the options to work with port sharing or not. Bruce will probably jump in and say yah or nay or something else.

In Linux its called The SO_REUSEPORT socket option [LWN.net]

In windows its called Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE - Win32 apps | Microsoft Learn

Edit I found it
Error Codes (capesoft.com)

WSAEADDRINUSE

(10048)

Address already in use .

Only one usage of each socket address (protocol/IP address/port) is normally permitted. This error occurs if an application attempts to bind a socket to an IP address/port that has already been used for an existing socket, or a socket that wasn’t closed properly, or one that is still in the process of closing. For server applications that need to bind multiple sockets to the same port number, consider using setsockopt (SO_REUSEADDR) . Client applications usually need not call bind at all - connect will choose an unused port automatically. When bind is called with a wild-card address (involving ADDR_ANY), a WSAEADDRINUSE error could be delayed until the specific address is “committed.” This could happen with a call to other function later, including connect , listen , WSAConnect or WSAJoinLeaf .

TLDR Port Sharing (SO_REUSEADDR) needs to be enabled, then each thread should be ok, provided it only acts on its own packet.

My understanding is the OS passes the “packet” to all the listeners sharing or BINDed to the port, and then the (threaded) listener which is waiting for the packet acts on it, whilst the others do nothing.

I don’t think this will be an issue for him as only one app - the API server - will be using a given port.

The clients will be sending HTTP requests to the machine hosting the API Server.

SSL certificates will not be an issue if he keeps the scope of the API server to his local LAN.

No problem.

1 Like

Doesnt Windows see each thread as a process?

Thats what it suggests here. Processes and Threads - Win32 apps | Microsoft Learn

An application consists of one or more processes. A process , in the simplest terms, is an executing program. One or more threads run in the context of the process. A thread is the basic unit to which the operating system allocates processor time. A thread can execute any part of the process code, including parts currently being executed by another thread.

If I have an app which uses the window threading model introduced in C6, and I start the app with a MDI Parent Frame, and then start 1 thread with a loop and nothing to accept external windows messages or notifications in order to shut down that loop, I can close the app and thus the MDI Parent Frame and the thread with the loop will remain running as a separate process.

So I think it does matter, however Bostjan might be lucky by not having to process many network packets which will mask this situation, because the thread issuing the packet and then waiting for the returning packet will arrive back before a new packet is sent out.

I could be wrong as I dont know enough about Bostjan’s app.

Edit.

I found this as well
About Processes and Threads - Win32 apps | Microsoft Learn

Each process provides the resources needed to execute a program. A process has a virtual address space, executable code, open handles to system objects, a security context, a unique process identifier, environment variables, a priority class, minimum and maximum working set sizes, and at least one thread of execution. Each process is started with a single thread, often called the primary thread , but can create additional threads from any of its threads.

So the primary thread MS refers to here is the thread 1 which is where the dct files are loaded before any MDI parent frame is called, which can then spawn additional threads.

So yeah its unclear.

You’re correct in that only one app may use one port at any given time.

In this situation, the API server will be using a port, say Port 88. On that machine, yes, that port is tied up until released.

correct. 20,19,18,17,16,15…

1 Like

no it doesn’t, and you are reading that wrong.

An “application” consists of 1 or more processes - so my exe might make use of say the SQL server exe, and so on. All the exe’s have to be working for my “application” to run. application in this context <> exe. Chrome Explorer uses an external process (not a thread) to host the HTML control. that’s a different architecture though.

One or more threads run in the context of the process.

threads run inside a process, and a process can have many threads.

no, it’s running as the same process. The process will only end when all the threads in that process end.

alas the faulty hypothesis leads to this faulty conclusion.

In the web server context, the server is listening on a thread, all it does is receive requests. each request spawns a new thread (not a new process). Each thread then formulates the response and sends it - by using the Webserver object from the listening thread.

2 Likes

Well, it took me few hours and my web API server inside my app is working, receiving POSTs with data, calling dll, returning data from it to web client. Neat!

Now I only have to process the received result in the client and I’m done. In which developer tool, besides CW (with 3rd party obviously), can you do that in one or two days?

Depending on what you are returning - JSON,XML,Etc…

JSON - jFiles
XML - xFiles

Anything else might be a custom parser.

1 Like

Heh, I meant it as a praise to Cw+3rdparty, rhetorical question :slight_smile:

So…
1 EXE/Application = 1 or many processes.

So where do the processes come from then?

I cant seem to nail down a decent definition of a process.

The other MS link suggests a process is started with a single thread, which is what we see with a typical clarion app, suggesting a clarion app is a single process, but I know when I start multiple threads in Clarion, I can see those listed separately in the task manager and process explorer, ergo a thread can be a process…

Anyway can nettalk do port sharing? :wink:

you are confusing your definition of “application” to mean “exe”. That’s probably a common mistake because in clarion an APP file is a “thing”, and it generally makes an EXE or DLL.
MS are using it in the context of “a group of programs”.

A process is a running instance of an Exe.

correct, IF it’s an EXE. Obviously multiple clarion apps can be used to create a single Process (one Exe, multiple DLL’s)

I don’t think this is true - I suspect you might have mis-interpreted something here. Task Manager in Windows shows each instance of an EXE as a single process. When you start multiple threads in Clarion you do not see multiple entries in Task Manager.

This is incorrect.

A Process has at least one thread, yes. Each thread is part of a process yes. But a thread cannot “be” a process. Threads are “internal” to an existing process.

Probably not in the way you are thinking. Multiple NetTalk web servers can share a common IP/Port by running under the Multi-Site Host process. But programs cannot “share” a ip:port address - neither technically, nor functionally.

I’m not confusing my definition of an application to mean an exe. I think you are confusing and introducing something else to further confuse the situation and perhaps your own thoughts, when you mention an App file. I’m well aware an App file can make an exe file, a dll file, or anything else the templates have been programmed to do, including writing class files with the extensions .clw, inc, int & more, manifest files and lots more I’m not going into details here because I dont want to be accused of confusing the situation any more.

Can you back that up with something from MS, because its their OS and their documentation which is causing the confusion

I think some screenshots will be in order to set the record straight.

Ok so Nettalk doesnt do shared ports [edit to avoid confusion] with other applications[/edit]. Thats what I thought.

From their documentation that you posted above.

no.

I’m not seeing that conclusion in the snippet you posted.

Perhaps this is the root of the confusion you are having?

cheers
Bruce