最近在做項(xiàng)目時(shí)厦取,用到socket,推送行情數(shù)據(jù)管搪,達(dá)到數(shù)據(jù)實(shí)時(shí)更新的目的虾攻。為了節(jié)約時(shí)間和成本,便使用輪子CocoaAsyncSocket框架,采用TCP連接進(jìn)行數(shù)據(jù)傳輸更鲁。和后臺(tái)約定采用自定義協(xié)議霎箍,采用byte方式傳輸,數(shù)據(jù)格式如下:
后臺(tái)定義的socket包格式如下:
根據(jù)后臺(tái)的要求澡为,必須使用byte進(jìn)行數(shù)據(jù)傳輸漂坏,所以必須對(duì)int和NSString轉(zhuǎn)換成byte(字節(jié)),最后把byte轉(zhuǎn)換成NSData進(jìn)行拼接缀壤,使用socket傳給后臺(tái)樊拓,下面是核心實(shí)現(xiàn)代碼:
- (void)connectSocket
{
? ? //判斷是否登錄
? ? if (![XBUserInfo manage].sessionKey) {
? ? ? ? return;
? ? }
? ? NSString *host = @"socket地址";
? ? UInt32 port = 端口號(hào);
? ? //創(chuàng)建GCDAsyncSocket
? ? NSError *error = nil;
? ? [self.socket connectToHost:host onPort:port error:&error];
? ? if (error != nil) {
? ? ? ? NSLog(@"%@",error);
? ? }
? ? //初始化纠亚,和服務(wù)器建立連接
? ? SignedByte protocolByte = 0x02;//協(xié)議編號(hào)
? ? SignedByte stateCodebyte = 0x01;//狀態(tài)碼
? ? //登錄data
? ? NSDictionary *dict = @{@"token":[XBUserInfo manage].sessionKey,@"deviceFlag":@(1)};
? ? //發(fā)送登錄的byte數(shù)據(jù)包
? ? [self sendMsgWithProtocolByte:protocolByte stateCodebyte:stateCodebyte content:dict];
}
- (void)sendMsgWithProtocolByte:(SignedByte)protocolByte stateCodebyte:(SignedByte)stateCodebyte content:(id)content
{
? //協(xié)議編號(hào)
? ? NSData *protocolData = [NSData oneByteToData:protocolByte];//自定義的字節(jié)轉(zhuǎn)data方法
//狀態(tài)碼
? ? NSData * stateCodebyteData = [NSData oneByteToData:stateCodebyte];//自定義的字節(jié)轉(zhuǎn)data方法
? ? NSData? *loginbyteData;
? ? if ([content isKindOfClass:[NSDictionary class]]) {//協(xié)議編號(hào)為登錄的data
? ? ? ? NSDictionary *dict = (NSDictionary *)content;
? ? ? ? NSString *loginStr = [NSString dictionaryToJson:dict];
? ? ? ? NSData *loginData = [loginStr dataUsingEncoding:NSUTF8StringEncoding];
? ? ? ? SignedByte *loginbyte = (SignedByte *)[loginData bytes];
? ? ? loginbyteData = [NSData dataWithBytes:loginbyte length:loginData.length];
? ? }else if ([content isKindOfClass:[NSString class]]){//協(xié)議編號(hào)為心跳包的data
? ? ? ? NSString *loginStr = (NSString *)content;
? ? ? ? NSData *loginData = [loginStr dataUsingEncoding:NSUTF8StringEncoding];
? ? ? ? SignedByte *loginbyte = (SignedByte *)[loginData bytes];
? ? ? loginbyteData = [NSData dataWithBytes:loginbyte length:loginData.length];
? ? ? ? NSLog(@"loginStr------------------------------%lu",(unsigned long)loginStr.length);
? ? }
? ? //消息長(zhǎng)度
? ? int len =(int)loginbyteData.length;
? ? NSData *lengthData =? [NSData intToByte:len];//自定義的int轉(zhuǎn)data方法
? ? NSMutableData *data = [NSMutableData data];
? ? [data appendData:protocolData];//協(xié)議編號(hào)
? ? [data appendData:stateCodebyteData];//狀態(tài)碼
? ? [data appendData:lengthData];//消息長(zhǎng)度
? ? [data appendData:loginbyteData];//內(nèi)容
? ? [self.socket? writeData:data withTimeout:-1 tag:111];
? ? [self.socket? readDataWithTimeout:-1 tag:101];
}
#pragma mark socket delegate
-(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port{
? ? NSLog(@"====>連接成功");
? ? [self threadStart];
? ? [self.socket? readDataWithTimeout:-1 tag:101];
}
-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err{
? ? NSLog(@"====>斷開連接");
? ? [self connectSocket];
? ? [self.socket? readDataWithTimeout:-1 tag:101];
}
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag{
? ? NSLog(@"====>寫入成功,是否連接失敗:====>%d",self.socket.isDisconnected);
? ? [self.socket? readDataWithTimeout:-1 tag:tag];
}
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{
? ? ? NSString *receiverStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
? ? ? NSLog(@"收到的數(shù)據(jù):------------------%@",receiverStr);
? ? [self.socket? readDataWithTimeout:-1 tag:tag];
}
//心跳包發(fā)送
- (void)threadStart
{
? ? if (!_connectTimer) {
? ? ? ? self.connectTimer =? [NSTimer scheduledTimerWithTimeInterval:5 target:self selector:@selector(heartBeat) userInfo:nil repeats:YES];
? ? ? ? [[NSRunLoop mainRunLoop] addTimer: self.connectTimer forMode:NSDefaultRunLoopMode];
? ? }
}
- (void)heartBeat
{
? ? NSLog(@"~~~開始心跳了~~~");
? ? SignedByte protocolByte = 0x01;//協(xié)議編號(hào)為心跳包
? ? SignedByte stateCodebyte = 0x01;//狀態(tài)碼
? ? [self sendMsgWithProtocolByte:protocolByte stateCodebyte:stateCodebyte content:@""];
}
遇到的最大的坑:聲明Byte類型時(shí)塘慕,應(yīng)和后臺(tái)保持一持,這里后臺(tái)使用的是SignedByte(有符號(hào)的字節(jié)類型)蒂胞。數(shù)據(jù)類型不一樣图呢,會(huì)導(dǎo)致發(fā)生內(nèi)容不正確,就不能接收到后臺(tái)發(fā)來的數(shù)據(jù)骗随。
---------------------
作者:碼農(nóng)甲乙丙
來源:CSDN
原文:https://blog.csdn.net/u012852597/article/details/81951592
版權(quán)聲明:本文為博主原創(chuàng)文章蛤织,轉(zhuǎn)載請(qǐng)附上博文鏈接!