Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
199 lines (128 sloc) 6.52 KB

PKWebSocket / WebSocket client for Cocoa

Implementation of the WebSocket protocol on top of the CocoaAsyncSocket for Cocoa. I used Zimt and cocoa-websocket project as basic for the this re-implementation.

I wanted to support multiple versions of the WebSocket protocol, make possible to easily add new protocol versions and to be able to influence handshake requests and so on.

Project is done as Static library which makes it usable in ARC/Non-ARC environments.


I follow the terms in the specification to divide project in to the three layers.

  1. High-level public API defined in the PKWebSocket. At this layer you work with the messages which you send and receive. PKWebSocketMessage is an envelope object to be possible add binary messages for the RFC6455 version of the protocol.

All API at this layer is PUBLIC.

  1. Handlers layer where handshakes & frames are handled and translated to messaeges. Also socket connection is here to read/write frames.

All API at this layer is PRIVATE.

  1. Frame parsers layer implements actual parsing of the raw data from sockets. Validates frames and sends them to the Handler layer.

All API at this layer is PRIVATE.


There are few utility classes:

  • PKHTTPResponse - encapsulate HTTP response
  • PKHTTPRequest - encapsulate HTTP request
  • PKWebSocketURL - NSURL sub-class making sure of correct parsing WebSocket URLs
  • PKWebSocketMessage - Wrapper around Data or String for compatibility
  • Crypto & Base64 categories


In order to add new protocol version there are 2 classes to implement.

If version introduce new handshake (opening/closing) a sub-class of the PKWebSocketHandler class is necessary You only need to override handshake frame methods:

- (BOOL)validateHandshakeResponse:(PKHTTPResponse *)response error:(NSError **)outError;
- (PKHTTPRequest *)handshakeRequestWithURL:(PKWebSocketURL *)anURL error:(NSError **)outError;
- (NSData *)handshakeResponseFrameBoundary;

You can add headers to your handshake request and validate your handshake response by overriding the appropriate methods.

If version introduce new framing you need to implement that framing in new PKWebSocketFrameParser sub-class. You should override init method and especially methods:

- (void)processData:(NSData *)data;
- (NSData *)textFramePayloadWithString:(NSString *)string;
- (NSData *)binaryFramePayloadWithData:(NSData *)aData;

Test suite

Project has a test suite. Most of the tests are Unit tests of the separate classes but for PKWebSocket there are bunch of the integration tests which requires you to be connected to internet as it connects to ws://


Following WebSocket protocol versions are currently supported. Also I've tested on the following servers. Secure WebSockets using TLS are supported.


  • Hixie 75 (Full support)
  • Hixie 76 (Full support)
  • TODO - RFC6455 (WIP - framing needs to be done)


  • em-websocket
  • ws://
  • TODO - Socket.IO & Node.js


Here is basic use case. Refer to the test suite for the PKWebSocket - PKWebSocketTests/PKWebSocketTests.m - for more info.

#import "PKWebSocket.h"
#import "PKWebSocketMessage.h"
#import "PKWebSocketHandler-Hixie76.h"

NSString *url = @"ws://";
PKWebSocketHandlerHixie76 *handler = [[PKWebSocketHandlerHixie76 alloc] init];
PKWebSocket *ws = [[PKWebSocket alloc] initWithHandler:handler delegate:self];

NSError *error;
if ([ws openWithURLString:url error:&error]) {
  [ws send:[PKWebSocketMessage messageWithString:@"string to send"]];

Delegate methods

On the delegate WebSocket calls following methods if you opt for them:

- (void)webSocket:(PKWebSocket *)webSocket didFailWithError:(NSError *)error;
- (void)webSocketDidOpen:(PKWebSocket *)webSocket;
- (void)webSocketDidClose:(PKWebSocket *)webSocket;
- (void)webSocket:(PKWebSocket *)webSocket didReceiveMessage:(PKWebSocketMessage *)message;
- (void)webSocketDidSendMessage:(PKWebSocket *)webSocket;

Using secure WebSocket

In order to use secure WebSocket you need to use wss URL scheme and you will probably need to set some TLS settings.

NSMutableDictionary *tlsSettings = [NSMutableDictionary dictionaryWithCapacity:4];
[tlsSettings forKey:(NSString *)kCFStreamSSLPeerName];

// Allow expired certificates
[tlsSettings setObject:[NSNumber numberWithBool:YES]
                forKey:(NSString *)kCFStreamSSLAllowsExpiredCertificates];

// Allow self-signed certificates
[tlsSettings setObject:[NSNumber numberWithBool:YES]
                forKey:(NSString *)kCFStreamSSLAllowsAnyRoot];

// In fact, don't even validate the certificate chain
[tlsSettings setObject:[NSNumber numberWithBool:NO]
                forKey:(NSString *)kCFStreamSSLValidatesCertificateChain];

// Set it to the web socket
[websocket setTLSSetting:tlsSettings];

Requirements & Dependencies & Submodules

Get code & Contribute

I'm grateful for any contributions no matter if it's bug report or patch!


If you have GIT 1.7+ ...

git clone --recursive

or, earlier...

git clone
cd PKWebSocket
git submodule init
git submodule update

Adding to your project

You can add PKWebSocket to your project in two ways.

XCode 4.x sub-project

  1. Drag-Drop PKWebSocket.xcodeproj in your project
  2. Add libPKWebSocket.a to your Link Binary With Libraries You might need to add CFNetwork.framework as well.
  3. Add -ObjC and -all_load to your Other Linker Flags
  4. Add $(BUILT_PRODUCTS_DIR) to your Libray Search Paths & Header Search Paths, mark recursive

Now you should be able to compile your project with the PKWebSocket. You can validate settings by going to the Derived data folder where you should see libPKWebSocket.a and PKWebSocket directory with header files.

Get the static library binary release (TODO)

I first need to push the release.

Based on the projects