[Checkins] SVN: zc.ngi/branches/jim-dev/src/zc/ngi/doc/index.txt Explained real-life server implementation.

Jim Fulton jim at zope.com
Fri Sep 4 07:01:24 EDT 2009


Log message for revision 103529:
  Explained real-life server implementation.
  

Changed:
  U   zc.ngi/branches/jim-dev/src/zc/ngi/doc/index.txt

-=-
Modified: zc.ngi/branches/jim-dev/src/zc/ngi/doc/index.txt
===================================================================
--- zc.ngi/branches/jim-dev/src/zc/ngi/doc/index.txt	2009-09-04 11:01:13 UTC (rev 103528)
+++ zc.ngi/branches/jim-dev/src/zc/ngi/doc/index.txt	2009-09-04 11:01:23 UTC (rev 103529)
@@ -253,22 +253,92 @@
 Note that handlers created from generators can be used as servers
 directly.
 
-To actually get connections, we have to register a server with a
-listener. NGI implentations provide listener functions that take a
-server and return listener objects.
+Finally, we have to listen for connections on an address by calling an
+implementation's listener method.  NGI comes with 2 implementations,
+an impplementation based on the standard asyncore module,
+zc.ngi.async, and a testing implementation, zc.ngi.testing.  To
+listen for real network connections on localhost port 8000, we'd use::
 
-NGI implementations provide a listener method, that takes an address
-and a server.  When testing servers, we'll often use the
+    >>> import zc.ngi.async
+
+    >>> address = 'localhost', 8000
+    >>> listener = zc.ngi.async.listener(address. Echo)
+
+.. test it
+
+    >>> exec(src)
+    >>> class EC:
+    ...     def connected(self, connection):
+    ...         connection.setHandler(self)
+    ...         conection.write('test data')
+    ...     input = ''
+    ...     def handle_input(self, connection, data):
+    ...         self.input += data
+    ...         if self.input == 'TEST DATA':
+    ...             print self.input
+    ...             connection.close()
+
+    >>> import zc.ngi.blocking
+    >>> zc.ngi.blocking.request(zc.ngi.async.connect, address, EC)
+
+The listener call returns immediately.  The servicing of requests is
+done in a separate daemon thread provided by ``zc.ngi.async``.
+
+Listener objects, returned from an impementation's listener function,
+provide methods for controlling servers.  The connections method
+returns an iterable of open connections to a server:
+
+    >>> list(listener.connections())
+    []
+
+We can stop listening by calling a listener's close method:
+
+    >>> listener.close()
+
+.. test it
+
+    >>> zc.ngi.blocking.request(zc.ngi.async.connect, address, EC)
+
+There's also a ``close_wait`` method that stops listening and waits
+for a given period of time for clients to finish on their own before
+closing them.
+
+NGI doesn't keep the main thread running
+----------------------------------------
+
+An important thing to note about NGI is that it doesn't provide
+support for maintaining the main application thread. The threads it
+creates for itself are "daemon" threads, meaning they don't keep an
+application running.  If a main program ended with an implentation's
+listener call. the program would likely exit before the listener had a
+chance to get and service any connections.
+
+It's up to us to keep an application running. Some frameworks provide
+a ``loop_forever`` call. The closest thing in NGI is::
+
+    import threading
+    event = Threading.Event()
+    event.wait()
+
+If you wanted to provide a way to gracefully shut down an application,
+you'd provide some communication channel, such as a signnal handler,
+that closed any listeners and then set the event blocking the main
+thread from executing.
+
+Testing servers
+---------------
+
+When testing servers, we'll often use the
 ``zc.ngi.testing.listener`` function:
 
-    >>> listener = zc.ngi.testing.listener('echo', Echo)
+    >>> listener = zc.ngi.testing.listener(address, Echo)
 
 Generally, the address will either be a host/port tuple or the name of
 a unix domain socket, although an implementation may define a custom
 address representation.  The ``zc.ngi.testing.listener`` function will
 take any hashable address object.
 
-We can connect to a testing listener using it's connect method:
+We can connect to a *testing* listener using it's connect method:
 
     >>> connection = listener.connect()
 
@@ -297,12 +367,6 @@
     >>> connection.write('take this')
     got 'TAKE THIS'
 
-Listeners provide two methods for controlling servers.  The
-``connections`` method returns an iterator of open connections. The
-``close`` method is used to stop a server, immediately, or after current
-connections have been closed.  See the reference sections of the
-documentation for more information.
-
 Implementing clients
 ====================
 



More information about the checkins mailing list