Download source files - 12 Kb
Asynchronous IO within ISAPI modules
Asynchronous IO under ISAPI is often viewed as something of a black art. But it's actually quite straight forward and it will yield the highest level of performance and scalability for your application.
A project to demonstrate Asynchronous IO
Browsing the Code Project site I stumbled across an example ISAPI project by Jorge Lodos Vigil which demonstrated sending back a page of HTML and an image. Two different types of data are returned by Jorges' ISAPI. The page is contained in an in-memory buffer while image is contained in a file on disk. Sending a buffer of data to a client and sending a file to a client just happen to encompass the two possible ways to send data asynchronously using the ISAPI API -
The ImageServer ISAPI extension essentially brokers requests for images from some hidden directory. ImageServer satisfies those requests by returning a page of HTML containing an IMG element that has, as it's source, the ImageServer extension. The source URL is specially formatted to let ImageServer know that it should send back the actual image instead of a containing page.
Two ways to perform asynchronous IO
Within the context of an ISAPI module there are two ways to recieve or send data asynchronously. You can use
WriteClient to read/write an arbitrary buffer of data to the client asynchronously or you can use
TransmitFile to send a file to a client asynchronously.
TransmitFile is a Win32 function which is accessed by using the ISAPI function
ServerSupportFunction and specifying the
The MSDN online library provides a good overview of asynchronous IO but in general you will need to perform these steps:
There's really only one other thing to keep in mind about asynchronous IO. That is whatever data is being sent to the client must survive until a completion notification is received. Which means it's almost always going to be placed on the heap.
- Setup a callback through which you will be notified when an IO completion event occurs.
- Start the asynchronous IO.
HSE_STATUS_PENDING from the
- When IO completes cleanup any context information and notify IIS you're done with this session.
This last requirement usually entails the most grief from a design standpoint. The extreme levels of performance and reliability required from ISAPI extensions precludes a design that constantly accesses the heap. Limiting access to the heap is often accomplished by implementing pools of buffer objects that are re-used.
ImageServers requirements are not as stringent. When ImageServer needs a buffer, or transmission context, it simply creates it on the heap. Likewise when it's finished with a buffer is just destroys it. Although creating a protected buffer pool is not difficult it would distract from the central purpose of ImageServer - which is to demonstrate basic asynchronous IO.
Tour of the code
The code is simple and heavily commented so it should be easy to understand. Here are the highlights of what you'll find.
- There is one main class
CImageServer which encapsulates all the functionality required for this application. This class is declared in
Server.h and implemented in
- A single static instance of
CImageServer resides in
ImageServer.cpp. Also in this file are the main entry points for the ISAPI DLL -
HttpExtensionProc. They are all basic boiler plate code except
HttpExtensionProc which delegates it's behavior
- There are two other classes which serve as transmission contexts for the asynchronous IO calls. The first is
CFilePacket which is a context for
TransmitFile. The second is
tWriteClientPacket, which is actually a structure not a class. It serves as a context for, you guessed it,
tWriteClientPacket are declared as nested classes/structures inside the declaration of
CImageServer. There was no real need for this but it makes the code a little cleaner as those classes are only used inside the functions of
CImageServer works is best accomplished by reading the source. Everything starts with
CImageServer::ServiceRequest and the comments will guide you from there.
As with any ISAPI module you'll have to locate the DLL in some path your web server has access too - with execute permissions. You'll also need a directory containing images that matches whatever you've hard coded into <!-- Author Bio Starts -->
About the author
The company I work for, Financial Insight Systems Inc., specializes in creating high performance internet applications using Microsoft Back Office products. I have a MCSD, with certifications in Visual C++ and SQL Server, and for the last five years most of my time has been spent developing ISAPI modules and Winsock based client/server solutions. Suggestions and comments are welcome. <!-- Author Bio Ends -->