美文网首页iOS开发技术
关于GCDAsyncSocket的一些个人理解

关于GCDAsyncSocket的一些个人理解

作者: _我和你一样 | 来源:发表于2018-03-31 21:53 被阅读76次

GCDAsyncSocket

GCDAsyncSocket 的读写都是异步的不会阻塞线程。

socket读写都是数据流,这个流一直存在,心跳不是必须的。如果不断开这个流通道就一直存在,读取和写入都通过这个流通道。

tag不参与流数据的传递,只是为了本地管理方便,是GCDAsyncSocket内部实现数据调度的一个东西,方便用户给数据打标记,方便读取。

发送信息在底层都是会被拆分成很细小的数据包发出去的,因此接受到的数据可以不是一次性接受完的。

每次可能收到一部分数据。读取时我们可能指定条件触发读取数据的方法。比如读取多长的数据就触发,又比如碰到回车断行数据就触发。

也可以收到数据就触发,然后处理这部分数据。

连接socket不必多说,主动调用才可以。链接socket会触发代理方法。

发送消息,会触发写消息的代理方法。每发送一个消息,就应该有一个读取消息。

读消息有很多种,指定读取的条件会根据条件触发读消息的代理。

可以这么理解。主动调用读消息,它就一直在那里可能是在后台一直读,当读到指定的条件时,触发代理方法。

如果处理完一次消息还要继续读取下次进来的数据,就要继续主动调用读数据的方法,会根据读数据的条件触发代理方法。

用到的代理方法大致如下:

//socket成功连接到才会服务器调用
  -(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port;
 //接受到新的socket连接才会调用
  - (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket;
 //读取数据,有数据就会调用
  - (void)readDataWithTimeout:(NSTimeInterval)timeout tag:(long)tag;
 //直到读到这个长度的数据,才会触发代理
  - (void)readDataToLength:(NSUInteger)length withTimeout:(NSTimeInterval)timeout tag:(long)tag; 
 //直到读到data这个边界,才会触发代理 
  - (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag;
 //有socket断开连接调用
  - (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err;

发消息时,通常我们有确保我们没有和服务器断开,如果断开了根据需要重连。

客户端要维持自己的心跳,来让服务器知道我们还连着。所谓心跳包就是开一个计时器,定时发送指定的信息。

服务器判断 时间间隔,如果超过一定的时间,服务器没收到来自客户端的信息,服务端就会端口链接。

我们在socket链接之后,就可以发送心跳包了。

[sock readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1 tag:0];是读取到边界的意思。当读取到边界时会触发代理方法。

封包处理:

数据包的封装,是需要一定的格式的,这个要和服务端协商一致。封装数据包时,要根据格式封装。

比如这个,先封装一个数据头,指定实际发送的数据内容的大小,自身的一些标志信息。以及一些分界标志等。后面是具体的数据。

像这里的数据报头,先转成json 再转成data 而不是直接转data发出去的。因为服务端要对报头进行json解析。

当然也可能是其他数据格式,比如protobuf消息数据,对象数据等。

/*封装报文**/
- (void)sendData:(NSData *)data :(NSString *)type toClinet:(NSString *)target;
{
    NSUInteger size = data.length;
    
    NSMutableDictionary *headDic = [NSMutableDictionary dictionary];
    [headDic setObject:type forKey:@"type"];
    [headDic setObject:@"CinentA" forKey:@"CinentID"];
    [headDic setObject:target forKey:@"targetID"];
    [headDic setObject:[NSString stringWithFormat:@"%ld",size] forKey:@"size"];
    NSString *jsonStr = [self dictionaryToJson:headDic];
    NSData *lengthData = [jsonStr dataUsingEncoding:NSUTF8StringEncoding];
    NSMutableData *mData = [NSMutableData dataWithData:lengthData];
    //分界
    [mData appendData:[GCDAsyncSocket CRLFData]];
    
    [mData appendData:data];
    
    
    //第二个参数,请求超时时间
    [self.clinetSocket writeData:mData withTimeout:-1 tag:0];
    
}
//字典转为Json字符串
- (NSString *)dictionaryToJson:(NSDictionary *)dic
{
    NSError *error = nil;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:&error];
    return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}

客户端要做的主要是:

  • 链接服务器,并维持心跳 维持心跳不是必须的
  • 封包,给服务器发送消息
  • 接受处理服务器的信息

服务端要做的主要是:

  • 数据包的拆解,
  • 数据的分发
  • 用户的调用
  • 每个用户的心跳刷新 维持心跳不是必须的

相关文章

网友评论

  • 1条大菜狗:心跳包,并不是在客户端开启定时器,定时发送,时间间隔应该是根据当前交互频率动态计算时间间隔的,还有一点,客户端的连接,能够自己检测连接和断开情况吗?

本文标题:关于GCDAsyncSocket的一些个人理解

本文链接:https://www.haomeiwen.com/subject/rdpncftx.html