I have some newbie questions about sockets.
1. What are queue depth for? It's not a quantity of clients that can connect to server simultaniously, is it?
2. Is there limit of open connections to one multi-server?
3. How can server to know when client close/drop connection?
Is there READ event in $KEY or maybe something else?
1. queue depth is the number of clients that can be trying to get a connection simultaneously. When one connection is established, it frees up one entry from this queue.
2. One limit is the number of file-descriptors (open files) the user has.
3. When you try to read from that socket, you'll get an error and hence go to $ZTRAP.
James A Self
If, for example, you have 20 server jobs jobs ready to handle the next request on port 80 each with a queue depth of 5, can you then queue up 100 requests or only 5? Would that result in lost requests if a job errored out and halted?
If you maintain many server jobs to handle HTTP requests, is it better to set the queue depth to 1 for each?
If you have two server jobs waiting on the same port with queue depth of 5 and two requests arrive before either can be serviced, which job handles the second request?
You cannot have more than one process listening to a port. That one server can queue up to 5 requests in its queue, which means none of the requests will be lost if there are at most 5 simultaneous requests. So, if there are 100 requests at the same moment, you would lose 95 of them, but this is an incredible rate. If the server has the time to process some of the requests (and take them out of the queue) between the requests, none will be lost.
Hope this helps,
"...cannot have more than one process listening..." Which leads to the real problem - since GT.M cannot handle the traditional technique of spawning another process to handle the request (because it cannot pass the socket connection) the server process that initially received the connection must process it. If the request may take a while then the queue may fill up and overflow. The only reasonable way around this seems to be to use a queue length of 1, close the listening queue after a connection is received and start another process to listen for the next request. This creates a not insignificant window between the initial request entering the queue and the new job creating a new queue of length 1 where connection requests will fail.
Questions for nergis:
1) Is the above accurate?
2) Is/Should GT.M get the ability to pass the socket off to a Jobbed process?
3) Is there a better way to handle potentially high volume/lengthy request processing listening?
James A Self
My design for a web server based on the documentation that Frans posted was to maintain some minimum number of server jobs (10? to start) waiting to OPEN the designated port and listen for the next request. On accepting a connection each job would CLOSE its listen before processing the request. It would also job out additional jobs (5?) if the number of free jobs fell below a certain number (5?) or if the total fell below the minimum). After processing one request it would purge out any extra stack levels and local variables and start over waiting to OPEN the port. This loosely follows what I know about the basic operation of Apache except I think that Apache has a master process which does the listening on all ports and hands off processing of each request to one of its children. We do something similar in our DTM based HTTP server.
Nergis' answer to my previous question made this design appear to be not feasible. I hope that is not true an that someone can shed some light on these questions for us.
Your plan to have 1 job listening and 9 waiting should cut down the window of exposure somewhat, especially since it eliminates the overhead involved in creating a new process (at least we're not on VMS). I presume the 9 processes would be waiting for the OPEN to succeed (or USE? don't have any code in front of me right now...). Unless you want to have potentially long response times to some requests you would still need to use a queue length of 1 though (correct?). Also, you still have a window from the time one request is made while the listening process is getting the initial connection to the time it closes the listening socket and one of the 9 other processes "wakes up" and completes the OPEN/USE listen request. This still seems like it would be significant under moderate to heavy loads.
I presume the queue length limit of 5 is arbitrary and could be expanded. Now, if it were just useful. It still seems to me that the key is to be able to create another process to handle the request and use an algorithm such you described for Apache. Of course, for Web Serving one should just use Apache...
I too look forward to the additional insight that I am sure negis/sanchez will provide.
OUCH! This cannot be! A limit of 5 simultaneous requests is absurdly low for handling HTTP and makes it sound like GTM sockets implementation is simply unsuitable for developing a reliable high speed MUMPS web server.. On web pages with graphics or frames or layers or applets, etc., a single web browser could readily exceed 5 simultaneous requests if not routinely throttled down to 4.
I knew that only one process could listen on a port, but I believe that any number can wait in line to be that one. I had hoped that if there was always a second job waiting to listen and the listening job closed the listen as soon as it began to service a connect request, then there could be no lost requests.
For HTTP, if there is any gap at all of no one listening between one server job accepting a connection and the next server job taking over the listen then a web server will begin to lose requests and behave unreliably with a very small number of users.
Frans S.C. Witte
First some remarks on the GT.M Socket Device Interface:
1) The maximum queue depth is 5.
Since at most one process listens at a port, this limits the number of queued requests to 5.
2) There is a distinction between the M device (in GT.M an arbitrry string), and the TCP port.
Multiple processes can try to connect to the same TCP port. However, only one will succeed. A second process will obtain the listen port as soon as the first process closes the listen socket. The "latency" involved depends (among others) on the way GT.M implemented the OPEN.
3) Each process could listen with a queue-depth of 5. Queued requests will show up on the WRITE /WAIT(nTime). So it is up to the application to handle them (before the M device is closed).
However for simplicity, and in order to ensure that requests are handled in the order in whch they arrive, it seems best to use a queue depth of 1.
4) I am not sure that you will loose CONNECTION requests in the interval between closing the listen socket and re-OPEN by a next process. Setting up a connection is by definition "time consuming", and usually the client will "wait" for the connection to be established (and possibly retry). You can easily try this by first starting a client, and then starting the server.
On the other hand the implementation method used by Sanchez may limit the maximum number of requests that can be handled per unit of time.
5) GT.M implements most of the MDC proposal.
This proposal assumes that there is a socket pool that is shared among concurrently executing M processes. Sanchez deliberately decided NOT to implement this. Their implementaion model is very different from the traditional M model, and Sanchez carefully tried to minimize the amount of required interaction between GT.M processes (e.g. no deamons).
I am convinced that the (un)importance of this non-conformance is outweighted by the costs (both in terms of implementation, and in terms of runtime behaviour).
This brings me to another issue (also mentioned by Bob).
Give me one good reason (other than academic) to implement a HTTP server in GT.M, when powerfull webservers such as Apache (OpenSource!) are available. You can interface to GT.M using anything that is capable of setting up a TCP connection. We use Java Server Pages for that purpose (but pick your favorite).
Decoupling has additional advantages such as security (cf "GT.M Security" by Bhaskar, in the Documentation area of the GT.M project), and the ability to run the GT.M processes on different machines (including OpenVMS, as we do).
We consider this "a better way to achieve high volume requests ...".
Frans S.C. Witte
James A Self
Thanks for the input Frans (apparently directed at multiple previous messages, including some of mine). Your documentation and examples on handling sockets were instrumental in helping me get started with TCP connections from GT.M altogether.
My primary reason for wanting to implement an HTTP server in GT.M is that it seemed to be the most reliable and direct route of development towards a high performance M web server. It was the obvious route for me given that I have been working daily for about 7 years now with MUMPS based HTTP servers that we implemented in DTM.
Our early experience with HTTP suggested that a server model that does not provide continuity of listening between requests will fail noticeably due to the staccato nature of HTTP even with a very small volume of traffic. I have not yet tested GT.M for this problem and from the responses to questions on this subject it appears that perhaps no one else has either.
Actually, I stopped just short of this test because of this question and other difficulties and questions that arose as I began converting MHTTP (our server) and selected applications from DTM to GT.M. Instead, I decided to first investigate the possibilities of interfacing via CGI because that seems to offer a much simpler practical starting point for familiarizing with the new and richer environment of Linux and Apache and GT.M.
Frans S.C. Witte
" ... interfacing via CGI ... seemt to offer a much simpler practical starting point ..."
This may be particulairly true for GT.M, because it behaves as an "odrinary" process, and interacts seemlessly with other processes, regardless of their programming language.
"If you interface to GT.M via TCP from ... something called from Apache it seems to me that you still have the same problem ..."
This is only partially true. What remains is the fact that only one process can listen on a particular port. However, by using "intermediate logic" (eg java servlets) one could have multiple GT.M processes that each listen on a different port, while the servlets pass the requests to one of these ports on a revolving basis. All ideas that you expressed before e.g. starting servers
dynamically, could be achieved, provided the servlets "know" which port range that can use (you could even have the servlet start another listener if servlet and "GT.M server" reside on the same machine).
"What protocol do you use between JSP and GT.M ..."
The HTML code is generated at the GT.M side, and simply written (WRITE) to the socket device. The java servlet simply "pipes" that data to the client. HTTP headers / trailers are easily added by calling standard "methods" of the java servlet.
Applets are used less frequently, because one cannot rely on the availability of a particular version of the java virtual machine at the particular client, and forcing the client-side to download the plug-in when it is needed may not help attracting customers to what you really want to sell.
As far as sample code is concerned, I am not a JSP specialist, but I could ask one of our colleages to provide some examples that even I do understand.
Frans S.C. Witte