socket是一种http的长连接请求,只是发送的数据格式要符合协议标准
/* From RFC:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|I|S|S|S| (4) |A| (7) | (16/64) |
|N|V|V|V| |S| | (if payload len==126/127) |
| |1|2|3| |K| | |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
| Extended payload length continued, if payload len == 127 |
+ - - - - - - - - - - - - - - - +-------------------------------+
| |Masking-key, if MASK set to 1 |
+-------------------------------+-------------------------------+
| Masking-key (continued) | Payload Data |
+-------------------------------- - - - - - - - - - - - - - - - +
: Payload Data continued ... :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Payload Data continued ... |
+---------------------------------------------------------------+
*/
1、发送数据
连接开启后会发送一次请求参数
将request里的内容封装成NSData
-(void)didConnect;
{
CFHTTPMessageRef request = CFHTTPMessageCreateRequest(NULL, CFSTR("GET"), (__bridge CFURLRef)_url, kCFHTTPVersion1_1);
// Set host first so it defaults
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Host"), (__bridge CFStringRef)(_url.port ? [NSString stringWithFormat:@"%@:%@", _url.host, _url.port] : _url.host));
NSMutableData *keyBytes = [[NSMutableData alloc] initWithLength:16];
SecRandomCopyBytes(kSecRandomDefault, keyBytes.length, keyBytes.mutableBytes);
if ([keyBytes respondsToSelector:@selector(base64EncodedStringWithOptions:)]) {
_secKey = [keyBytes base64EncodedStringWithOptions:0];
} else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
_secKey = [keyBytes base64Encoding];
#pragma clang diagnostic pop
}
assert([_secKey length] == 24);
// Apply cookies if any have been provided
NSDictionary * cookies = [NSHTTPCookie requestHeaderFieldsWithCookies:[self requestCookies]];
for (NSString * cookieKey in cookies) {
NSString * cookieValue = [cookies objectForKey:cookieKey];
if ([cookieKey length] && [cookieValue length]) {
CFHTTPMessageSetHeaderFieldValue(request, (__bridge CFStringRef)cookieKey, (__bridge CFStringRef)cookieValue);
}
}
// set header for http basic auth
if (_url.user.length && _url.password.length) {
NSData *userAndPassword = [[NSString stringWithFormat:@"%@:%@", _url.user, _url.password] dataUsingEncoding:NSUTF8StringEncoding];
NSString *userAndPasswordBase64Encoded;
if ([keyBytes respondsToSelector:@selector(base64EncodedStringWithOptions:)]) {
userAndPasswordBase64Encoded = [userAndPassword base64EncodedStringWithOptions:0];
} else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
userAndPasswordBase64Encoded = [userAndPassword base64Encoding];
#pragma clang diagnostic pop
}
_basicAuthorizationString = [NSString stringWithFormat:@"Basic %@", userAndPasswordBase64Encoded];
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Authorization"), (__bridge CFStringRef)_basicAuthorizationString);
}
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Upgrade"), CFSTR("websocket"));
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Connection"), CFSTR("Upgrade"));
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Key"), (__bridge CFStringRef)_secKey);
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Version"), (__bridge CFStringRef)[NSString stringWithFormat:@"%ld", (long)_webSocketVersion]);
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Origin"), (__bridge CFStringRef)_url.SR_origin);
if (_requestedProtocols) {
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Protocol"), (__bridge CFStringRef)[_requestedProtocols componentsJoinedByString:@", "]);
}
[_urlRequest.allHTTPHeaderFields enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
CFHTTPMessageSetHeaderFieldValue(request, (__bridge CFStringRef)key, (__bridge CFStringRef)obj);
}];
NSData *message = CFBridgingRelease(CFHTTPMessageCopySerializedMessage(request));
CFRelease(request);
[self _writeData:message];
}
- (void)_writeData:(NSData *)data;
{
[self assertOnWorkQueue];
if (_closeWhenFinishedWriting) {
return;
}
[_outputBuffer appendData:data];
[self _pumpWriting];
}
- 发送一般数据
- (void)send:(id)data;
{
NSAssert(self.readyState != SR_CONNECTING, @"Invalid State: Cannot call send: until connection is open");
// TODO: maybe not copy this for performance
data = [data copy];
dispatch_async(_workQueue, ^{
if ([data isKindOfClass:[NSString class]]) {
[self _sendFrameWithOpcode:SROpCodeTextFrame data:[(NSString *)data dataUsingEncoding:NSUTF8StringEncoding]];
} else if ([data isKindOfClass:[NSData class]]) {
[self _sendFrameWithOpcode:SROpCodeBinaryFrame data:data];
} else if (data == nil) {
[self _sendFrameWithOpcode:SROpCodeTextFrame data:data];
} else {
assert(NO);
}
});
}
- 将数据转换成标准协议格式的NSData
static const size_t SRFrameHeaderOverhead = 32;
- (void)_sendFrameWithOpcode:(SROpCode)opcode data:(id)data;
{
[self assertOnWorkQueue];
if (nil == data) {
return;
}
NSAssert([data isKindOfClass:[NSData class]] || [data isKindOfClass:[NSString class]], @"NSString or NSData");
size_t payloadLength = [data isKindOfClass:[NSString class]] ? [(NSString *)data lengthOfBytesUsingEncoding:NSUTF8StringEncoding] : [data length];
NSMutableData *frame = [[NSMutableData alloc] initWithLength:payloadLength + SRFrameHeaderOverhead];
if (!frame) {
[self closeWithCode:SRStatusCodeMessageTooBig reason:@"Message too big"];
return;
}
uint8_t *frame_buffer = (uint8_t *)[frame mutableBytes];
// set fin
frame_buffer[0] = SRFinMask | opcode;
BOOL useMask = YES;
#ifdef NOMASK
useMask = NO;
#endif
if (useMask) {
// set the mask and header
frame_buffer[1] |= SRMaskMask;
}
size_t frame_buffer_size = 2;
const uint8_t *unmasked_payload = NULL;
if ([data isKindOfClass:[NSData class]]) {
unmasked_payload = (uint8_t *)[data bytes];
} else if ([data isKindOfClass:[NSString class]]) {
unmasked_payload = (const uint8_t *)[data UTF8String];
} else {
return;
}
if (payloadLength < 126) {
frame_buffer[1] |= payloadLength;
} else if (payloadLength <= UINT16_MAX) {
frame_buffer[1] |= 126;
*((uint16_t *)(frame_buffer + frame_buffer_size)) = EndianU16_BtoN((uint16_t)payloadLength);
frame_buffer_size += sizeof(uint16_t);
} else {
frame_buffer[1] |= 127;
*((uint64_t *)(frame_buffer + frame_buffer_size)) = EndianU64_BtoN((uint64_t)payloadLength);
frame_buffer_size += sizeof(uint64_t);
}
if (!useMask) {
for (size_t i = 0; i < payloadLength; i++) {
frame_buffer[frame_buffer_size] = unmasked_payload[i];
frame_buffer_size += 1;
}
} else {
uint8_t *mask_key = frame_buffer + frame_buffer_size;
SecRandomCopyBytes(kSecRandomDefault, sizeof(uint32_t), (uint8_t *)mask_key);
frame_buffer_size += sizeof(uint32_t);
// TODO: could probably optimize this with SIMD
for (size_t i = 0; i < payloadLength; i++) {
frame_buffer[frame_buffer_size] = unmasked_payload[i] ^ mask_key[i % sizeof(uint32_t)];
frame_buffer_size += 1;
}
}
assert(frame_buffer_size <= [frame length]);
frame.length = frame_buffer_size;
[self _writeData:frame];
}
- 数据封装
typedef enum {
SROpCodeTextFrame = 0x1,
SROpCodeBinaryFrame = 0x2,
// 3-7 reserved.
SROpCodeConnectionClose = 0x8,
SROpCodePing = 0x9,
SROpCodePong = 0xA,
// B-F reserved.
} SROpCode;
// 第一个字节设置fin
uint8_t *frame_buffer = (uint8_t *)[frame mutableBytes];
// set fin
frame_buffer[0] = SRFinMask | opcode;
// 设置mask
frame_buffer[1] |= SRMaskMask;
//设置payload
if (payloadLength < 126) {
frame_buffer[1] |= payloadLength;
} else if (payloadLength <= UINT16_MAX) {
frame_buffer[1] |= 126;
*((uint16_t *)(frame_buffer + frame_buffer_size)) = EndianU16_BtoN((uint16_t)payloadLength);
frame_buffer_size += sizeof(uint16_t);
} else {
frame_buffer[1] |= 127;
*((uint64_t *)(frame_buffer + frame_buffer_size)) = EndianU64_BtoN((uint64_t)payloadLength);
frame_buffer_size += sizeof(uint64_t);
}
// 设置mask_key
uint8_t *mask_key = frame_buffer + frame_buffer_size;
SecRandomCopyBytes(kSecRandomDefault, sizeof(uint32_t), (uint8_t *)mask_key);
frame_buffer_size += sizeof(uint32_t);
// TODO: could probably optimize this with SIMD
for (size_t i = 0; i < payloadLength; i++) {
frame_buffer[frame_buffer_size] = unmasked_payload[i] ^ mask_key[i % sizeof(uint32_t)];
frame_buffer_size += 1;
}
读取数据
-(void)_readFrameContinue;
{
assert((_currentFrameCount == 0 && _currentFrameOpcode == 0) || (_currentFrameCount > 0 && _currentFrameOpcode > 0));
[self _addConsumerWithDataLength:2 callback:^(SRWebSocket *self, NSData *data) {
__block frame_header header = {0};
const uint8_t *headerBuffer = data.bytes;
assert(data.length >= 2);
if (headerBuffer[0] & SRRsvMask) {
[self _closeWithProtocolError:@"Server used RSV bits"];
return;
}
uint8_t receivedOpcode = (SROpCodeMask & headerBuffer[0]);
BOOL isControlFrame = (receivedOpcode == SROpCodePing || receivedOpcode == SROpCodePong || receivedOpcode == SROpCodeConnectionClose);
if (!isControlFrame && receivedOpcode != 0 && self->_currentFrameCount > 0) {
[self _closeWithProtocolError:@"all data frames after the initial data frame must have opcode 0"];
return;
}
if (receivedOpcode == 0 && self->_currentFrameCount == 0) {
[self _closeWithProtocolError:@"cannot continue a message"];
return;
}
header.opcode = receivedOpcode == 0 ? self->_currentFrameOpcode : receivedOpcode;
header.fin = !!(SRFinMask & headerBuffer[0]);
header.masked = !!(SRMaskMask & headerBuffer[1]);
header.payload_length = SRPayloadLenMask & headerBuffer[1];
headerBuffer = NULL;
if (header.masked) {
[self _closeWithProtocolError:@"Client must receive unmasked data"];
}
size_t extra_bytes_needed = header.masked ? sizeof(_currentReadMaskKey) : 0;
if (header.payload_length == 126) {
extra_bytes_needed += sizeof(uint16_t);
} else if (header.payload_length == 127) {
extra_bytes_needed += sizeof(uint64_t);
}
if (extra_bytes_needed == 0) {
[self _handleFrameHeader:header curData:self->_currentFrameData];
} else {
[self _addConsumerWithDataLength:extra_bytes_needed callback:^(SRWebSocket *self, NSData *data) {
size_t mapped_size = data.length;
#pragma unused (mapped_size)
const void *mapped_buffer = data.bytes;
size_t offset = 0;
if (header.payload_length == 126) {
assert(mapped_size >= sizeof(uint16_t));
uint16_t newLen = EndianU16_BtoN(*(uint16_t *)(mapped_buffer));
header.payload_length = newLen;
offset += sizeof(uint16_t);
} else if (header.payload_length == 127) {
assert(mapped_size >= sizeof(uint64_t));
header.payload_length = EndianU64_BtoN(*(uint64_t *)(mapped_buffer));
offset += sizeof(uint64_t);
} else {
assert(header.payload_length < 126 && header.payload_length >= 0);
}
if (header.masked) {
assert(mapped_size >= sizeof(_currentReadMaskOffset) + offset);
memcpy(self->_currentReadMaskKey, ((uint8_t *)mapped_buffer) + offset, sizeof(self->_currentReadMaskKey));
}
[self _handleFrameHeader:header curData:self->_currentFrameData];
} readToCurrentFrame:NO unmaskBytes:NO];
}
} readToCurrentFrame:NO unmaskBytes:NO];
}