摘要
Mars 是微信官方的终端基础组件,是一个使用 C++ 编写的业务性无关,平台性无关的基础组件。目前已接入微信 Android、iOS、Mac、Windows、WP 等客户端。下面主要分析iOS端样例消息调用流程。
Mars 结构
官方样图- COMM:基础库,包括socket、线程、消息队列、协程等基础工具;
- XLOG:通用日志模块,充分考虑移动终端的特点,提供高性能、高可用、安全性、容错性的日志功能;
- SDT:网络诊断模块;
- STN:信令传输网络模块,负责终端与服务器的小数据信令通道。包含了微信终端在移动网络上的大量优化经验与成果,经历了微信海量用户的考验。
其中STN(信令传输网络)为核心模块。
下面主要分析STN模块消息通讯流程:
- 官方demo 地址: https://github.com/Tencent/mars
- 如何编译Mars: http://www.jianshu.com/p/09d04f12203a
- 自己部署服务端JDK安装:http://www.jianshu.com/p/8a95bbe70099
消息核心流程:一个消息任务以startTask开始,onTaskEnd结束。中间通过StnCallBack::Req2Buf与StnCallBack::Buf2Resp分别处理客户端的请求和响应的相关操作,比如数据处理,服务端响应和状态检测等等。
客户端发送/接受
发送
数据传输格式为:google 的 protocol buffer。protocol buffer是google的一个开源项目,它是用于结构化数据串行化的灵活、高效、自动的方法,例如XML,不过它比xml更小、更快、也更简单。你可以定义自己的数据结构,然后使用代码生成器生成的代码来读写这个数据结构。你甚至可以在无需重新部署程序的情况下更新数据结构。
- protocol buffer : https://github.com/google/protobuf
iOS端发送调用方法: requestSendData
-(NSData*)requestSendData {
SendMessageRequest *sendMsgRequest = [SendMessageRequest new];
sendMsgRequest.from = [self username];
sendMsgRequest.to = @"all";
sendMsgRequest.text = _textField.text;
sendMsgRequest.accessToken = @"123456";
sendMsgRequest.topic = _conversation.topic;
LOG_INFO(kModuleViewController, @"send msg to topic:%@", _conversation.notice);
NSData* data = [sendMsgRequest data];
dispatch_async(dispatch_get_main_queue(), ^{
_textField.text = @"";
});
return data;
}
数据处理:StnCallBack::Req2Buf
bool StnCallBack::Req2Buf(int32_t _taskid, void* const _user_context, AutoBuffer& _outbuffer, int& _error_code, const int _channel_select) {
NSData* requestData = [[NetworkService sharedInstance] Request2BufferWithTaskID:_taskid userContext:_user_context];
if (requestData == nil) {
requestData = [[NSData alloc] init];
}
_outbuffer.AllocWrite(requestData.length);
_outbuffer.Write(requestData.bytes,requestData.length);
return requestData.length > 0;
}
接收
-(int)onPostDecode:(NSData*)responseData {
SendMessageResponse *sendMsgResponse = [SendMessageResponse parseFromData:responseData error:nil];
dispatch_async(dispatch_get_main_queue(), ^{
NSString *recvtext = [NSString stringWithFormat:@"%@ : %@", sendMsgResponse.from, sendMsgResponse.text];
[self.messages addObject:recvtext];
[self.tableView reloadData];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.messages.count-1 inSection:0];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
});
return sendMsgResponse.errCode == 0 ? 0 : -1;
}
数据处理:StnCallBack::Buf2Resp
int StnCallBack::Buf2Resp(int32_t _taskid, void* const _user_context, const AutoBuffer& _inbuffer, int& _error_code, const int _channel_select) {
int handle_type = mars::stn::kTaskFailHandleNormal;
NSData* responseData = [NSData dataWithBytes:(const void *) _inbuffer.Ptr() length:_inbuffer.Length()];
NSInteger errorCode = [[NetworkService sharedInstance] Buffer2ResponseWithTaskID:_taskid ResponseData:responseData userContext:_user_context];
if (errorCode != 0) {
handle_type = mars::stn::kTaskFailHandleDefault;
}
return handle_type;
}
消息存储
消息存储是用字典存储,taskID为key,数据包为value。
- (void)addObserver:(id<UINotifyDelegate>)observer forKey:(NSString *)key {
[controllers setObject:observer forKey:key];
}
- (void)addCGITasks:(CGITask*)cgiTask forKey:(NSString *)key {
[tasks setObject:cgiTask forKey:key];
}
服务端推送
当TaskID 为0时候,默认为推送。
调用方法:notifyPushMessage
- (void)notifyPushMessage:(NSData*)pushData withCmdId:(int)cmdId {
MessagePush* messagePush = [MessagePush parseFromData:pushData error:nil];
if (messagePush != nil) {
dispatch_async(dispatch_get_main_queue(), ^{
NSString *recvtext = [NSString stringWithFormat:@"%@ : %@", messagePush.from, messagePush.content];
[self.messages addObject:recvtext];
[self.tableView reloadData];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.messages.count-1 inSection:0];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
});
}
}
数据处理:StnCallBack::OnPush
void StnCallBack::OnPush(int32_t _cmdid, const AutoBuffer& _msgpayload) {
if (_msgpayload.Length() > 0) {
NSData* recvData = [NSData dataWithBytes:(const void *) _msgpayload.Ptr() length:_msgpayload.Length()];
[[NetworkService sharedInstance] OnPushWithCmd:_cmdid data:recvData];
}
}
数据存储:cmdID
- (void)addPushObserver:(id<PushNotifyDelegate>)observer withCmdId:(int)cmdId {
LOG_INFO(kNetwork, @"add pushObserver for cmdId:%d", cmdId);
[pushrecvers setObject:observer forKey:[NSString stringWithFormat:@"%d", cmdId]];
}
完成一个任务
调用方法:
- (int)onTaskEnd:(uint32_t)tid errType:(uint32_t)errtype errCode:(uint32_t)errcode {
NSLog(@"%ld %ld %ld ",tid, errtype, errcode);
return 0;
}
处理方法:StnCallBack::OnTaskEnd
int StnCallBack::OnTaskEnd(int32_t _taskid, void* const _user_context, int _error_type, int _error_code) {
return (int)[[NetworkService sharedInstance] OnTaskEndWithTaskID:_taskid userContext:_user_context errType:_error_type errCode:_error_code];
}
待续。
网友评论