四。 接着来讲讲数据的读和写:
当建立连接成功后,就会循环调用这么一个方法:
//读取http头部
- (void)_readHTTPHeader;
{
if (_receivedHTTPHeaders == NULL) {
//序列化的http消息
_receivedHTTPHeaders = CFHTTPMessageCreateEmpty(NULL, NO);
}
//不停的add consumer去读数据
[self _readUntilHeaderCompleteWithCallback:^(SRWebSocket *self, NSData *data) {
//拼接数据,拼到头部
CFHTTPMessageAppendBytes(_receivedHTTPHeaders, (const UInt8 *)data.bytes, data.length);
//判断是否接受完
if (CFHTTPMessageIsHeaderComplete(_receivedHTTPHeaders)) {
SRFastLog(@“Finished reading headers %@”, CFBridgingRelease(CFHTTPMessageCopyAllHeaderFields(_receivedHTTPHeaders)));
[self _HTTPHeadersDidFinish];
} else {
//没读完递归调
[self _readHTTPHeader];
}
}];
}
记得楼主之前写过一篇即时通讯下数据粘包、断包处理实例(基于CocoaAsyncSocket),因此抛出一个问题,WebSocket需要处理数据的断包和粘包么?
答案是基本不需要。引用知乎上的一段回答:
RFC规范指出,WebSocket是一个message-based的协议,它可以自动将数据分片,并且自动将分片的数据组装。
也就是说,WebSocket的RFC标准是不会产生粘包、断包问题的。无需应用层开发人员关心缓存以及手工组装message。
然而理想与现实的不一致:RFC规范与实现的不一致,现实当中有几个问题:
每个message可以是一个或多个分片。message不记录长度,分片才记录长度。
message最大的长度可以达到 9,223,372,036,854,775,807 字节,是由于Payload的数据长度有63bit的限制。
很多WebSocket的实现其实并不按照标准的RFC实现完全,很多仅仅实现了50%就拿来用了。这就导致了,在WebSocket实现上的最大长度很难达到这个大小,于是,很多API的实现上是会有限制的,可能会限制你的发送的长度,也可能会把过长的数据直接以流式发送。
而SRWebSocket中实现的方式上彻底解决了数据粘包,断包的可能。
数据是通过CFStream流的方式回调回来的,每次拿到流数据,都是先放在数据缓冲区中,然后去读当前消息帧的头部,得到当前数据包的大小,然后再去创建消费者对象consumer,去读取缓冲区指定数据包大小的内容,读完才会回调给我们上层用户,所以,我们如果用SRWebSocket完全不需要考虑数据断包、粘包的问题,每次到达的数据,都是一条完整的数据。
接着我们大概来看看这个流程:
//读取CRLFCRLFBytes,直到回调回来
- (void)_readUntilHeaderCompleteWithCallback:(data_callback)dataHandler;
{
[self _readUntilBytes:CRLFCRLFBytes length:sizeof(CRLFCRLFBytes) callback:dataHandler];
}
//读取数据 CRLFCRLFBytes,边界符
- (void)_readUntilBytes:(const void *)bytes length:(size_t)length callback:(data_callback)dataHandler;
{
// TODO optimize so this can continue from where we last searched
//消费者需要消费的数据大小
stream_scanner consumer = ^size_t(NSData *data) {
__block size_t found_size = 0;
__block size_t match_count = 0;
//得到数据长度
size_t size = data.length;
//得到数据指针
const unsigned char *buffer = data.bytes;
for (size_t i = 0; i 《 size; i++ ) {
//匹配字符
if (((const unsigned char *)buffer)[i] == ((const unsigned char *)bytes)[match_count]) {
//匹配数+1
match_count += 1;
//如果匹配了
if (match_count == length) {
//读取数据长度等于 i+ 1
found_size = i + 1;
break;
}
} else {
match_count = 0;
}
}
//返回要读取数据的长度,没匹配成功就是0
return found_size;
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
全部0条评论
快来发表一下你的评论吧 !