大家好,欢迎来到IT知识分享网。
IM之Socket
IM之Socket
说到即时通讯,就会让人想到socket,然而现在三方的即时通讯SDK也是数不胜数。本文就简单说一下github上非常火热的CocoaAsyncSocket,我们会利用这个库来实现消息(文本消息,图片消息,以及数据流)发送接收。
CocoaAsyncSocket
- UDP 是无连接的,面向消息的,提供高效率服务。不会使用块的合并优化算法, 由于UDP支持的是一对多的模式,在每个UDP包中有消息头,这样,对于接收端来说,就容易进行区分处理了。
首先我们创建了一个SocketManager来管理我们的socket相关的事务,客户端代码如下:
typedef NS_ENUM(NSUInteger, MessageType) { MessageTypeTxt, MessageTypePic, MessageTypeDataStream, //音视频 数据流 }; / @class GCDAsyncSocket; @protocol SocketManagerDelegate <NSObject> @optional - (void)socket:(GCDAsyncSocket *_Nonnull)socket didReadData:(NSData *_Nonnull)data withType:(MessageType)messageType; @end @interface SocketManager : NSObject @property (strong, nonatomic, readonly, nonnull) NSString *host; @property (readonly) uint16_t port; @property (weak, nonatomic, nullable) id<SocketManagerDelegate>delegate; + (_Nonnull instancetype)shareManager; - (BOOL)connectToHost:( NSString *_Nonnull )host onPort:(uint16_t)port; - (void)disConnect; - (void)sendMessage:(NSData *_Nonnull)aMessageData withMessageType:(MessageType)messageType; @end
这样SocketManager就管理了我们的连接和数据封包发送,下面是消息封包发送
-(void)sendMessage:(NSData *)aMessageData withMessageType:(MessageType)messageType { NSUInteger size = aMessageData.length; NSMutableDictionary *headInfo = [NSMutableDictionary dictionary]; [headInfo setObject:@(messageType) forKey:@"messageType"]; [headInfo setObject:[NSString stringWithFormat:@"%ld",size] forKey:@"size"]; NSString *jsonStr = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:headInfo options:NSJSONWritingPrettyPrinted error:nil] encoding:NSUTF8StringEncoding]; NSData *headData = [jsonStr dataUsingEncoding:NSUTF8StringEncoding]; NSMutableData *sendData = [NSMutableData dataWithData:headData]; //分界 [sendData appendData:[GCDAsyncSocket CRLFData]]; [sendData appendData:aMessageData]; //第二个参数,请求超时时间 [socket writeData:sendData withTimeout:-1 tag:0]; }
正如我们所想的那样,在数据包里面我们加入了消息头信息和边界,这样我们在拆包的时候就能根据边界和消息头顺利的拆包,不至于分不清数据包的大小而少包、多包。其他的话就是一些sockect的代理方法,包括消息发送成功的回调,读取到消息的回调等。我们在socket连接成功的时候去发送心跳包,在断开连接的时候去做一个断线重连:
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port { NSLog(@"连接到服务器"); self.heartTimer = [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(sendHeartPackage:) userInfo:nil repeats:YES]; } - (void)sendHeartPackage:(NSTimer *)timer { [self sendMessage:[[NSString stringWithFormat:@"cheater connected...%@",[NSDate date]] dataUsingEncoding:NSUTF8StringEncoding] withMessageType:MessageTypeTxt]; } - (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(nullable NSError *)err { NSLog(@"断开连接"); [self.heartTimer invalidate]; self.heartTimer = nil; if (err) { //断线 或者其他原因 [socket connectToHost:self.host onPort:self.port error:nil]; }else{ //手动断线 self->_host = nil; self->_port = 0; } }
我们这里实现客户端和服务器相互收发消息,拆包的代码如下:
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag { //先读取到当前数据包头部信息 if (!self.packageHeadInfo) { self.packageHeadInfo = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil]; if (!self.packageHeadInfo) { NSLog(@"error:当前数据包的头为空"); return; } NSUInteger packageLength = [self.packageHeadInfo[@"size"] integerValue]; //读到数据包的大小 [sock readDataToLength:packageLength withTimeout:-1 tag:0]; return; } //正式的包处理 NSUInteger packageLength = [self.packageHeadInfo[@"size"] integerValue]; //说明数据有问题 if (packageLength <= 0 || data.length != packageLength) { NSLog(@"error:当前数据包数据大小不正确"); return; } NSNumber *type = self.packageHeadInfo[@"messageType"]; if (self.delegate && [self.delegate respondsToSelector:@selector(socket:didReadData:withType:)]) { [self.delegate socket:socket didReadData:data withType:[type unsignedIntegerValue]]; } self.packageHeadInfo = nil; [sock readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1 tag:0]; }
我们首先是读取到边界线,然后去解析消息头里面的信息来判断本次接收到的数据是否可靠(无效,不完整)。
本文只是自己的一些理解,如您发现任何错误,欢迎留言指正~!
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/119430.html