1. socket 实例化方法
/**
* GCDAsyncSocket uses the standard delegate paradigm,
* but executes all delegate callbacks on a given delegate dispatch queue.
* This allows for maximum concurrency, while at the same time providing easy thread safety.
*
* You MUST set a delegate AND delegate dispatch queue before attempting to
* use the socket, or you will get an error.
*
* The socket queue is optional.
* If you pass NULL, GCDAsyncSocket will automatically create it's own socket queue.
* If you choose to provide a socket queue, the socket queue must not be a concurrent queue.
* If you choose to provide a socket queue, and the socket queue has a configured target queue,
* then please see the discussion for the method markSocketQueueTargetQueue.
*
* The delegate queue and socket queue can optionally be the same.
**/
- (id)init;
- (id)initWithSocketQueue:(dispatch_queue_t)sq;
- (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq;
- (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq socketQueue:(dispatch_queue_t)sq;
注意:the socket queue must not be a concurrent queue.
系统提供
3个Concurrent Queues
dispatch_queue_t aQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_queue_t aHQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); dispatch_queue_t aLQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
1个main queue
dispatch_queue_t mainQueue = dispatch_get_main_queue();
2. socket 接收消息 处理
/**********************************************delegate*********************************************************/
#pragma mark - 接收到消息
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
//转为明文消息
NSString *secretStr = [data base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
//去除'\n'
secretStr = [secretStr stringByReplacingOccurrencesOfString:@"\n" withString:@""];
//转为消息模型(具体传输的json包裹内容,加密方式,包头设定什么的需要和后台协商,操作方式根据项目而定)
ChatModel *messageModel = [ChatModel mj_objectWithKeyValues:secretStr];
//接收到服务器的心跳
if ([messageModel.beatID isEqualToString:TCP_beatBody]) {
//未接到服务器心跳次数置为0
_senBeatCount = 0;
NSLog(@"------------------接收到服务器心跳-------------------");
return;
}
//消息类型 (消息类型这里是以和服务器协商后自定义的通信协议来设定 , 包括字段名,具体的通信逻辑相关 . 当然也可以用数字来替代下述的字段名,使用switch效率更高)
ChatMessageType messageType = ChatMessageContentType_Unknow;
//普通消息类型
if ([messageModel.messageType isEqualToString:Message_Normal]) {
messageType = ChatMessageType_Normal;
//验证消息
}else if ([messageModel.messageType isEqualToString:Message_Validate]){
messageType = ChatMessageType_Validate;
//系统消息
}else if ([messageModel.messageType isEqualToString:Message_System]){
messageType = ChatMessageType_System;
//发送普通消息回执
}else if ([messageModel.messageType isEqualToString:Message_NormalReceipt]){
messageType = ChatMessageType_NormalReceipt;
//登录成功回执
}else if ([messageModel.messageType isEqualToString:Message_LoginReceipt]){
messageType = ChatMessageType_LoginReceipt;
//开始发送心跳
[self sendBeat];
//重新建立连接后 , 重置自动重连次数
autoConnectCount = TCP_AutoConnectCount;
//发送普通消息失败回执
}else if ([messageModel.messageType isEqualToString:Message_InvalidReceipt]){
messageType = ChatMessageType_InvalidReceipt;
//撤回消息回执
}else if ([messageModel.messageType isEqualToString:Message_RepealReceipt]){
messageType = ChatMessageType_RepealReceipt;
// 未知消息类型
}else{
messageType = ChatMessageContentType_Unknow;
}
#warning - 注意 ...
//此处可以进行本地数据库存储,具体的就不多解释 , 通常来讲 , 每个登录用户创建一个DB ,每个DB对应3张表足够 ,一张用于存储聊天列表页 , 一张用于会话聊天记录存储,还有一张用于好友列表/群列表的本地化存储. 但是注意的一点 , 必须设置自增ID . 此外,个人建议预留出10个或者20个字段以备将来增加需求,或者使用数据库升级亦可
//进行回执服务器,告知服务器已经收到该条消息(实际上是可以解决消息丢失问题 , 因为心跳频率以及网络始终是有一定延迟,当你断开的一瞬间,服务器并没有办法非常及时的获取你的连接状态,所以进行双向回执会更加安全,服务器推向客户端一条消息,客户端未进行回执的话,服务器可以将此条消息设置为离线消息,再次进行推送)
//消息分发,将消息发送至每个注册的Object中 , 进行相应的布局等操作
for (id delegate in self.delegates) {
if ([delegate respondsToSelector:@selector(didReceiveMessage:type:)]) {
[delegate didReceiveMessage:messageModel type:messageType];
}
}
}
详解注释
http://blog.csdn.net/qq_30513483/article/details/54668875
网友评论