ソースを参照

Documentation

Taddeus Kroes 12 年 前
コミット
5034eae47c
3 ファイル変更162 行追加17 行削除
  1. 128 6
      README.md
  2. 26 4
      connection.py
  3. 8 7
      server.py

+ 128 - 6
README.md

@@ -1,10 +1,55 @@
-**twspy** is a standalone implementation of web sockets for Python, defined by
-[RFC 6455](http://tools.ietf.org/html/rfc6455).
+About
+=====
 
 
-- The `websocket` class upgrades a regular socket to a web socket. A websocket
-  instance is a single end point of a connection. A `websocket` instance sends
-  and receives frames (`Frame` instances) as opposed to bytes (which are
-  sent/received in a regular socket).
+*twspy* is a standalone implementation of web sockets for Python, defined by
+[RFC 6455](http://tools.ietf.org/html/rfc6455). The incentive for creating this
+library is the absence of a layered implementation of web sockets outside the
+scope of web servers such as Apache or Nginx. *twspy* does not require any
+third-party programs or libraries outside Python's standard library. It
+provides low-level access to sockets, as well as high-level functionalities to
+easily set up a web server. Thus, it is both suited for quick server
+programming, as well as for more demanding applications that require low-level
+control over each frame being sent/received.
+
+Her is a quick overview of the features in this library:
+- Upgrading regular sockets to web sockets.
+- Building custom frames.
+- Messages, which are higher-level than frames (see "Basic usage").
+- Connections, which hide the handling of control frames and automatically
+  concatenate fragmented messages to individual payloads.
+- HTTP authentication during handshake.
+- An extendible server implementation.
+- Secure sockets using SSL certificates (for 'wss://...' URL's).
+- The possibility to add extensions to the web socket protocol. An included
+  implementation is [deflate-frame](http://tools.ietf.org/html/draft-tyoshino-hybi-websocket-perframe-deflate-06).
+
+
+Basic usage
+===========
+
+- The `websocket` class upgrades a regular socket to a web socket. A
+  `websocket` instance is a single end point of a connection. A `websocket`
+  instance sends and receives frames (`Frame` instances) as opposed to bytes
+  (which are sent/received in a regular socket).
+
+  Server example:
+
+        import twspy, socket
+        sock = twspy.websocket()
+        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+        sock.bind(('', 8000))
+        sock.listen()
+
+        client = sock.accept()
+        client.send(twspy.Frame(twspy.OPCODE_TEXT, 'Hello, Client!'))
+        frame = client.recv()
+
+  Client example:
+
+        import twspy
+        sock = twspy.websocket(location='/my/path')
+        sock.connect(('', 8000))
+        sock.send(twspy.Frame(twspy.OPCODE_TEXT, 'Hello, Server!'))
 
 
 - A `Connection` instance represents a connection between two end points, based
 - A `Connection` instance represents a connection between two end points, based
   on a `websocket` instance. A connection handles control frames properly, and
   on a `websocket` instance. A connection handles control frames properly, and
@@ -12,3 +57,80 @@
   frames). Messages are automatically converted to frames, and received frames
   frames). Messages are automatically converted to frames, and received frames
   are converted to messages. Fragmented messages (messages consisting of
   are converted to messages. Fragmented messages (messages consisting of
   multiple frames) are also supported.
   multiple frames) are also supported.
+
+  Example of an echo server (sends back what it receives):
+
+        import twspy
+
+        class EchoConnection(twspy.Connection):
+            def onopen(self):
+                print 'Connection opened at %s:%d' % self.sock.getpeername()
+
+            def onmessage(self, message):
+                print 'Received message "%s"' % message.payload
+                self.send(twspy.TextMessage(message.payload))
+
+            def onclose(self, message):
+                print 'Connection closed'
+
+        server = twspy.websocket()
+        server.bind(('', 8000))
+        server.listen()
+
+        while True:
+            client, addr = server.accept()
+            EchoConnection(client).receive_forever()
+
+  There are two types of messages: `TextMessage`s and `BinaryMessage`s. A
+  `TextMessage` uses frames with opcode `OPCODE_TEXT`, and encodes its payload
+  using UTF-8 encoding. A `BinaryMessage` just sends its payload as raw data.
+  I recommend using `TextMessage` by default, and `BinaryMessage` only when
+  necessary.
+
+  **Note:** For browser clients, you will probably want to use JSON encoding.
+  This could, for example, be implemented as follows:
+
+        import twspy, json
+
+        def msg(**data):
+            return twspy.TextMessage(json.dumps(data))
+
+        # create some connection `conn`...
+
+        conn.send(msg(foo='Hello, World!'))
+
+
+- The built-in `Server` implementation is very basic. It starts a new thread
+  with a `Connection.receive_forever()` loop for each client that connects. It
+  also handles client crashes properly. By default, a `Server` instance only
+  logs every event using Python's `logging` module. To create a custom server,
+  The `Server` class should be extended and its event handlers overwritten. The
+  event handlers are named identically to the `Connection` event handlers, but
+  they also receive an additional `client` argument. This argument is a
+  modified `Connection` instance, so you can invoke `send()` and `recv()`.
+
+  For example, the `EchoConnection` example above can be rewritten to:
+
+        import twspy
+
+        class EchoServer(twspy.Server):
+            def onopen(self, client):
+                print 'Client %s connected' % client
+
+            def onmessage(self, client, message):
+                print 'Received message "%s"' % message.payload
+                client.send(twspy.TextMessage(message.payload))
+
+            def onclose(self, client):
+                print 'Client %s disconnected' % client
+
+        EchoServer(8000).run()
+
+  The server can be stopped by typing CTRL-C in the command line. The
+  `KeyboardInterrupt` raised when this happens is caught by the server.
+
+
+Extensions
+==========
+
+TODO

+ 26 - 4
connection.py

@@ -9,12 +9,34 @@ from errors import SocketClosed, PingError
 
 
 class Connection(object):
 class Connection(object):
     """
     """
-    A Connection uses a websocket instance to send and receive (optionally
-    fragmented) messages, which are Message instances. Control frames are
+    A `Connection` uses a `websocket` instance to send and receive (optionally
+    fragmented) messages, which are `Message` instances. Control frames are
     handled automatically in the way specified by RFC 6455.
     handled automatically in the way specified by RFC 6455.
 
 
-    To use the Connection class, it should be extended and the extending class
-    should implement the on*() event handlers.
+    To use the `Connection` class, it should be extended and the extending
+    class should implement the on*() event handlers.
+
+    Example of an echo server (sends back what it receives):
+    >>> import twspy
+
+    >>> class EchoConnection(twspy.Connection):
+    >>>     def onopen(self):
+    >>>         print 'Connection opened at %s:%d' % self.sock.getpeername()
+
+    >>>     def onmessage(self, message):
+    >>>         print 'Received message "%s"' % message.payload
+    >>>         self.send(twspy.TextMessage(message.payload))
+
+    >>>     def onclose(self, message):
+    >>>         print 'Connection closed'
+
+    >>> server = twspy.websocket()
+    >>> server.bind(('', 8000))
+    >>> server.listen()
+
+    >>> while True:
+    >>>     client, addr = server.accept()
+    >>>     EchoConnection(client).receive_forever()
     """
     """
     def __init__(self, sock):
     def __init__(self, sock):
         """
         """

+ 8 - 7
server.py

@@ -18,17 +18,18 @@ class Server(object):
     Example usage:
     Example usage:
     >>> import twspy
     >>> import twspy
 
 
-    >>> class GameServer(twspy.Server):
+    >>> class EchoServer(twspy.Server):
     >>>     def onopen(self, client):
     >>>     def onopen(self, client):
-    >>>         # client connected
-
-    >>>     def onclose(self, client):
-    >>>         # client disconnected
+    >>>         print 'Client %s connected' % client
 
 
     >>>     def onmessage(self, client, message):
     >>>     def onmessage(self, client, message):
-    >>>         # handle message from client
+    >>>         print 'Received message "%s"' % message.payload
+    >>>         client.send(twspy.TextMessage(message.payload))
+
+    >>>     def onclose(self, client):
+    >>>         print 'Client %s disconnected' % client
 
 
-    >>> GameServer(8000).run()
+    >>> EchoServer(8000).run()
     """
     """
 
 
     def __init__(self, port, hostname='', loglevel=logging.INFO, protocols=[],
     def __init__(self, port, hostname='', loglevel=logging.INFO, protocols=[],