246 lines
8.6 KiB
ReStructuredText
246 lines
8.6 KiB
ReStructuredText
SocketRocket Objective-C WebSocket Client (beta)
|
||
================================================
|
||
A conforming WebSocket (`RFC 6455 <http://tools.ietf.org/html/rfc6455>`_)
|
||
client library.
|
||
|
||
`Test results for SocketRocket here <http://square.github.io/SocketRocket/results/>`_.
|
||
You can compare to what `modern browsers look like here
|
||
<http://tavendo.com/autobahn/testsuite/report/clients/index.html>`_.
|
||
|
||
SocketRocket currently conforms to all ~300 of `Autobahn
|
||
<http://autobahn.ws/testsuite/>`_'s fuzzing tests (aside from
|
||
two UTF-8 ones where it is merely *non-strict*. tests 6.4.2 and 6.4.4)
|
||
|
||
Features/Design
|
||
---------------
|
||
- TLS (wss) support. It uses CFStream so we get this for *free*
|
||
- Uses NSStream/CFNetworking. Earlier implementations used ``dispatch_io``,
|
||
however, this proved to be make TLS nearly impossible. Also I wanted this to
|
||
work in iOS 4.x. (SocketRocket only supports 5.0 and above now)
|
||
- Uses ARC. It uses the 4.0 compatible subset (no weak refs).
|
||
- Seems to perform quite well
|
||
- Parallel architecture. Most of the work is done in background worker queues.
|
||
- Delegate-based. Had older versions that could use blocks too, but I felt it
|
||
didn't blend well with retain cycles and just objective C in general.
|
||
|
||
Changes
|
||
-------
|
||
|
||
v0.3.1-beta2 - 2013-01-12
|
||
`````````````````````````
|
||
|
||
- Stability fix for ``closeWithCode:reason:`` (Thanks @michaelpetrov!)
|
||
- Actually clean up the NSStreams and remove them from their runloops
|
||
- ``_SRRunLoopThread``'s ``main`` wasn't correctly wrapped with
|
||
``@autoreleasepool``
|
||
|
||
v0.3.1-beta1 - 2013-01-12
|
||
`````````````````````````
|
||
|
||
- Cleaned up GCD so OS_OBJECT_USE_OBJC_RETAIN_RELEASE is optional
|
||
- Removed deprecated ``dispatch_get_current_queue`` in favor of ``dispatch_queue_set_specific`` and ``dispatch_get_specific``
|
||
- Dropping support for iOS 4.0 (it may still work)
|
||
|
||
|
||
Installing (iOS)
|
||
----------------
|
||
There's a few options. Choose one, or just figure it out
|
||
|
||
- You can copy all the files in the SocketRocket group into your app.
|
||
- Include SocketRocket as a subproject and use libSocketRocket
|
||
|
||
If you do this, you must add -ObjC to your "other linker flags" option
|
||
|
||
- For OS X you will have to repackage make a .framework target. I will take
|
||
contributions. Message me if you are interested.
|
||
|
||
|
||
Depending on how you configure your project you may need to ``#import`` either
|
||
``<SocketRocket/SRWebSocket.h>`` or ``"SRWebSocket.h"``
|
||
|
||
Framework Dependencies
|
||
``````````````````````
|
||
Your .app must be linked against the following frameworks/dylibs
|
||
|
||
- libicucore.dylib
|
||
- CFNetwork.framework
|
||
- Security.framework
|
||
- Foundation.framework
|
||
|
||
Installing (OS X)
|
||
-----------------
|
||
SocketRocket now has (64-bit only) OS X support. ``SocketRocket.framework``
|
||
inside Xcode project is for OS X only. It should be identical in function aside
|
||
from the unicode validation. ICU isn't shipped with OS X which is what the
|
||
original implementation used for unicode validation. The workaround is much
|
||
more rudimentary and less robust.
|
||
|
||
1. Add SocketRocket.xcodeproj as either a subproject of your app or in your workspace.
|
||
2. Add ``SocketRocket.framework`` to the link libraries
|
||
3. If you don't have a "copy files" step for ``Framework``, create one
|
||
4. Add ``SocketRocket.framework`` to the "copy files" step.
|
||
|
||
API
|
||
---
|
||
The classes
|
||
|
||
``SRWebSocket``
|
||
```````````````
|
||
The Web Socket.
|
||
|
||
.. note:: ``SRWebSocket`` will retain itself between ``-(void)open`` and when it
|
||
closes, errors, or fails. This is similar to how ``NSURLConnection`` behaves.
|
||
(unlike ``NSURLConnection``, ``SRWebSocket`` won't retain the delegate)
|
||
|
||
What you need to know
|
||
|
||
.. code-block:: objective-c
|
||
|
||
@interface SRWebSocket : NSObject
|
||
|
||
// Make it with this
|
||
- (id)initWithURLRequest:(NSURLRequest *)request;
|
||
|
||
// Set this before opening
|
||
@property (nonatomic, assign) id <SRWebSocketDelegate> delegate;
|
||
|
||
- (void)open;
|
||
|
||
// Close it with this
|
||
- (void)close;
|
||
|
||
// Send a UTF8 String or Data
|
||
- (void)send:(id)data;
|
||
|
||
@end
|
||
|
||
``SRWebSocketDelegate``
|
||
```````````````````````
|
||
You implement this
|
||
|
||
.. code-block:: objective-c
|
||
|
||
@protocol SRWebSocketDelegate <NSObject>
|
||
|
||
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message;
|
||
|
||
@optional
|
||
|
||
- (void)webSocketDidOpen:(SRWebSocket *)webSocket;
|
||
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error;
|
||
- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean;
|
||
|
||
@end
|
||
|
||
Known Issues/Server Todo's
|
||
--------------------------
|
||
- Needs auth delegates (like in NSURLConnection)
|
||
- Move the streams off the main runloop (most of the work is backgrounded uses
|
||
GCD, but I just haven't gotten around to moving it off the main loop since I
|
||
converted it from dispatch_io)
|
||
- Re-implement server. I removed an existing implementation as well because it
|
||
wasn't being used and I wasn't super happy with the interface. Will revisit
|
||
this.
|
||
- Separate framer and client logic. This will make it nicer when having a
|
||
server.
|
||
|
||
Testing
|
||
-------
|
||
Included are setup scripts for the python testing environment. It comes
|
||
packaged with vitualenv so all the dependencies are installed in userland.
|
||
|
||
To run the short test from the command line, run::
|
||
|
||
make test
|
||
|
||
To run all the tests, run::
|
||
|
||
make test_all
|
||
|
||
The short tests don't include the performance tests. (the test harness is
|
||
actually the bottleneck, not SocketRocket).
|
||
|
||
The first time this is run, it may take a while to install the dependencies. It
|
||
will be smooth sailing after that. After the test runs the makefile will open
|
||
the results page in your browser. If nothing comes up, you failed. Working on
|
||
making this interface a bit nicer.
|
||
|
||
To run from the app, choose the ``SocketRocket`` target and run the test action
|
||
(``cmd+u``). It runs the same thing, but makes it easier to debug. There is
|
||
some serious pre/post hooks in the Test action. You can edit it to customize
|
||
behavior.
|
||
|
||
.. note:: Xcode only up to version 4.4 is currently supported for the test
|
||
harness
|
||
|
||
TestChat Demo Application
|
||
-------------------------
|
||
SocketRocket includes a demo app, TestChat. It will "chat" with a listening
|
||
websocket on port 9900.
|
||
|
||
It's a simple project. Uses storyboard. Storyboard is sweet.
|
||
|
||
|
||
TestChat Server
|
||
```````````````
|
||
We've included a small server for the chat app. It has a simple function.
|
||
It will take a message and broadcast it to all other connected clients.
|
||
|
||
We have to get some dependencies. We also want to reuse the virtualenv we made
|
||
when we ran the tests. If you haven't run the tests yet, go into the
|
||
SocketRocket root directory and type::
|
||
|
||
make test
|
||
|
||
This will set up your `virtualenv <https://pypi.python.org/pypi/virtualenv>`_.
|
||
Now, in your terminal::
|
||
|
||
source .env/bin/activate
|
||
pip install git+https://github.com/tornadoweb/tornado.git
|
||
|
||
In the same terminal session, start the chatroom server::
|
||
|
||
python TestChatServer/py/chatroom.py
|
||
|
||
There's also a Go implementation (with the latest weekly) where you can::
|
||
|
||
cd TestChatServer/go
|
||
go run chatroom.go
|
||
|
||
Chatting
|
||
````````
|
||
Now, start TestChat.app (just run the target in the Xcode project). If you had
|
||
it started already you can hit the refresh button to reconnect. It should say
|
||
"Connected!" on top.
|
||
|
||
To talk with the app, open up your browser to `http://localhost:9000 <http://localhost:9000>`_ and
|
||
start chatting.
|
||
|
||
|
||
WebSocket Server Implementation Recommendations
|
||
-----------------------------------------------
|
||
SocketRocket has been used with the following libraries:
|
||
|
||
- `Tornado <https://github.com/facebook/tornado>`_
|
||
- Go's `WebSocket package <https://godoc.org/golang.org/x/net/websocket>`_ or Gorilla's `version <http://www.gorillatoolkit.org/pkg/websocket>`_
|
||
- `Autobahn <http://tavendo.com/autobahn/testsuite.html>`_ (using its fuzzing
|
||
client)
|
||
|
||
The Tornado one is dirt simple and works like a charm. (`IPython notebook
|
||
<http://ipython.org/ipython-doc/dev/interactive/htmlnotebook.html>`_ uses it
|
||
too). It's much easier to configure handlers and routes than in
|
||
Autobahn/twisted.
|
||
|
||
As far as Go's goes, it works in my limited testing. I much prefer go's
|
||
concurrency model as well. Try it! You may like it.
|
||
It could use some more control over things such as pings, etc., but I
|
||
am sure it will come in time.
|
||
|
||
Autobahn is a great test suite. The Python server code is good, and conforms
|
||
well (obviously). However for me, twisted would be a deal-breaker for writing
|
||
something new. I find it a bit too complex and heavy for a simple service. If
|
||
you are already using twisted though, Autobahn is probably for you.
|
||
|
||
Contributing
|
||
------------
|
||
We’re glad you’re interested in SocketRocket, and we’d love to see where you take it. Please read our `contributing guidelines <https://github.com/square/SocketRocket/blob/master/Contributing.md>`_ prior to submitting a Pull Request. |