Using NetStreams
In this page the basic techniques are explained. Reviewing the
samples packaged with the DLL you can see them in action.
The library has one "root" object which is helper and
also provider for a general functionality not applicable for any
other particular object in the library. Its name is NSMain.
It has several methods that create directly the other library objects
allowing
you to avoid using CreateObject or other ActiveX creation
facilities once you have one NSMain created by your code. This makes the code a bit more clear and also ensures
all the objects are created in the same COM apartment which may
improve the performance in many scenarios. Another important function
of this object is to initialize the WinSock library - while it
is "alive" the WinSock is initialized. You can think the
NSMain represents tha WinSock session. So the first step always will be creating one such object and
then asking it to provide whatever other objects you may need for
our work.
Although some applications may need only some lookup features,
most applications of NetStreams will include data transfer. We can
describe this as a set of several generalized steps.
A typical client connection:
- The application finds the service provider.
In this step for instance the application may need to
resolve a DNS name or perform an IRDA devices lookup. After
doing so it will have a ready-to-use address of the desired
service provider or it will "know" that it cannot be
found. Depending on the specifics the application may need to
create and initialize a SocketStream object at certain point
of the process. If it does not require this the application
creates/inits a SocketStream object ready to be connected to
the discovered address.
- Connects to it
In this step the application uses the address from the
first step to connect the already created SocketStream object
to the server. This may fail if the server is unreachable,
down or otherwise inaccessible at this very moment. If the
connection is successful the application creates a SFStream
object (from newObejcts ActiveX
Pack1) and sets the connected
socket to it. Alternatively applications written in C++ (or
another language with native COM interfaces support) can query
the connected SocketStream object for IStream interface.
- Transfers data
Now the applications performs read and write operations
over the SFStream object (or directly through the IStream
interface - C++ apps. only). Depending on the server protocol
(for example HTTP, POP3, SMTP, IMAP and so on) the application
may use binary or text read/write methods of SFStream in
different order and with different options - as appropriate
for the application and protocol requirements.
- Closes the connection
When the work is done it is time to close the SocketStream
object and thus close the connection (it can be already closed
by the server depending on the protocol used - for example
HTTP behaves this way if no "keep-alive" is
requested). Further the application does whatever clean up work it
needs to do.
A typical server:
- Determine the address on which the services will be
provided.
This may be needed or may be not - depending on the server
implementation and mostly depending on the
parameters/configuration it accepts (i.e. it is a matter of
design).
- Server binds to the address(es).
The application creates a SocketStream object, initializes
it for the address family and protocol on which it will serve.
Then uses the SocketStream.Bind to bind the socket to the
address. Depending on the protocol the application may need to
specify service name or a port number in the address for
binding. Some protocols (IP for example) allow the system to
choose free port or some sort of service id and the
application is able to learn it by examining the socket's
address after successful binding (SocketStream.SocketAddress
property).
- Application begins to listen and accept the incoming
connections.
In this step the application usually calls the Listen
method to instruct WinSock listen for incoming connections and
then uses the Accept method to obtain them as they occur.
Depending on the server application's structure it may use
threads or process all the connections in the main thread. The
latter method most often will involve usage of non-blocking
mode. Non-blocking mode is a little harder to implement
compared to blocking mode where the code needed is really
simple, but sometimes for servers servicing small number of
clients it may be more efficient than implementing threads.
The SocketStream.Accept method returns a new
SocketStream object which represents the received connection
with a client. The application uses it just like on the client
side after the point where it is connected.
- Servicing the connection.
As the application obtains the new SocketStream
obejct from the Accept method it needs to create SFStream and
set the SocketStream to it (or alternatively C++ apps. can
query it for IStream interface and use it directly).
Read/write operations are done like in a client application
and as the protocol implemented requires.
- Finish the work with a particular connection.
After finishing the conversation with a client the server
application disconnects the socket and "forgets" it.
If a thread per-client is used then the thread may complete,
if the work is done in the main thread then perhaps the
application keeps the currently connected/serviced
SocketStream objects in some kind of pool (array, collection
etc.). Thus the application removes the SocketStream object
from that pool.
- Server shutdown.
The server application closes the listening socket that was
bound to an address in step 2 and releases all the resources
involved in servicing clients.
|