下載AsyncSockethttps://github.com/robbiehanson/CocoaAsyncSocket類庫(kù)毒费,將RunLoop文件夾下的AsyncSocket.h, AsyncSocket.m, AsyncUdpSocket.h, AsyncUdpSocket.m 文件拷貝到自己的project中
添加CFNetwork.framework, 在使用socket的文件頭
#import <Foundation/Foundation.h>
#import "AsyncUdpSocket.h"
#import <CommonCrypto/CommonDigest.h>
typedef void (^dataBlock)(NSDictionary *response, NSString *responseString);
@interface UDPSocketSingleton : NSObject<AsyncUdpSocketDelegate>
@property (nonatomic, strong) AsyncUdpSocket *socket; // socket
@property (nonatomic, copy) NSString *socketHost; // socket的Host
@property (nonatomic, assign) UInt16 socketPort; // socket的prot
@property (nonatomic, strong) NSTimer *connectTimer; // 計(jì)時(shí)器
@property (nonatomic, strong) NSDictionary *socketResult;
@property (nonatomic, strong) dataBlock receiveData;
/**
* block回調(diào)方法途戒,為了回調(diào)的時(shí)候少寫(xiě)代碼
*/
- (void)receiveData:(dataBlock)block;
+ (UDPSocketSingleton *)sharedInstance; // 單例
- (void)socketConnectHost; // socket連接
-(void)cutOffSocket; // 斷開(kāi)socket連接
@end
通信中,涉及到byte字節(jié)流的解析呜呐,這個(gè)就需要根據(jù)實(shí)際情況的字節(jié)流數(shù)組中各個(gè)字節(jié)的要求和代表的數(shù)據(jù)內(nèi)容來(lái)進(jìn)行解析了。這些需要跟后臺(tái)服務(wù)器溝通悍募,確定每個(gè)字節(jié)代表了什么
#import "UDPSocketSingleton.h"
static UDPSocketSingleton *sharedInstance = nil;
@implementation UDPSocketSingleton
+ (UDPSocketSingleton *)sharedInstance {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
#pragma mark - 連接host
- (void)socketConnectHost {
/**
* 初始化
*/
self.socket = [[AsyncUdpSocket alloc] initIPv4];
_socket.delegate = self;
NSError *error = nil;
/**
* 所連接的服務(wù)器ip地址 socketHost 和 端口號(hào):socketPort
*/
[self.socket connectToHost:self.socketHost onPort:self.socketPort error:&error];
/**
* 允許廣播信息
*/
[self.socket enableBroadcast:YES error:&error];
//啟動(dòng)接收線程
[self.socket receiveWithTimeout:-1 tag:1];
[self sendMessage];
/**
* 建立定時(shí)器蘑辑,每隔50s像服務(wù)器發(fā)送心跳包
*
* longConnectToSocket:心跳包調(diào)用方法,在longConnectToSocket方法中進(jìn)行長(zhǎng)連接坠宴,并向服務(wù)器發(fā)送的訊息
*
* TimeInterval:心跳包執(zhí)行間隔時(shí)間
*
*/
self.connectTimer = [NSTimer scheduledTimerWithTimeInterval:50 target:self selector:@selector(longConnectToSocket) userInfo:nil repeats:YES];// 在longConnectToSocket方法中進(jìn)行長(zhǎng)連接需要向服務(wù)器發(fā)送的訊息
/**
* 啟動(dòng)定時(shí)器
*/
[self.connectTimer fire];
}
#pragma mark - 心跳包調(diào)用方法
- (void)longConnectToSocket {
// NSLog(@"心跳包信息發(fā)送");
[self sendMessage];
}
#pragma mark - AsyncUDPSocketDelegate
#pragma mark 信息發(fā)送成功成功回調(diào)
- (void)onUdpSocket:(AsyncUdpSocket *)sock didSendDataWithTag:(long)tag{
// NSLog(@"已發(fā)送消息tag = %ld",tag);
}
#pragma mark 接收信息回調(diào)
- (BOOL)onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port
{
// NSLog(@"接收到消息");
if (data.length < 5) {
return NO;
}
/**
* 解析數(shù)據(jù)
*/
[self dataToString:data];
return YES;
}
#pragma mark - 接收到數(shù)據(jù)進(jìn)行回調(diào)
- (void)receiveData:(dataBlock)block {
self.receiveData = block;
}
- (void)onUdpSocket:(AsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError *)error
{
//無(wú)法發(fā)送時(shí),返回的異常提示信息 do something
// NSLog(@"error1");
}
-(void)onUdpSocket:(AsyncUdpSocket *)sock didNotReceiveDataWithTag:(long)tag dueToError:(NSError *)error
{
//無(wú)法接收時(shí)以躯,返回異常提示信息 do something
// NSLog(@"error2,%@",error);
if (error.code == 57) {
[self cutOffSocket];
[self socketConnectHost];
}
}
- (void)sendMessage {
[self.socket receiveWithTimeout:-1 tag:1];
/**
* 獲取通過(guò)Keychain保存的唯一不可變的UUID,否則UUID在刪除程序重新裝入后會(huì)變化
*/
NSString *uuidStr = [[NSUserDefaults standardUserDefaults] objectForKey:@"clientId"];
NSMutableData *writer=[[NSMutableData alloc]init];
// NSLog(@"%@",uuidStr);
int version = 1;
int num = 1;
int cmd = 0;
int length= 0000;
NSData *data = [uuidStr dataUsingEncoding:NSUTF8StringEncoding];
Byte *byte = (Byte *)[data bytes];
Byte by[16];
CC_MD5(byte, (int)data.length, by);//md5加密
[writer appendBytes:&version length:1];
[writer appendBytes:&num length:1];
[writer appendBytes:&cmd length:1];
[writer appendBytes:by length:16];
[writer appendBytes:&length length:2];
[self.socket sendData:writer withTimeout:-1 tag:1];
}
#pragma mark - 數(shù)據(jù)解析
- (void)dataToString:(NSData *)data {
//已經(jīng)處理完畢
int responseBytes = 32;
[data getBytes:&responseBytes range:NSMakeRange(2, 1)];
// NSLog(@"\n\n----------------------接收信息:%d------------------\n\n",responseBytes);
/**
* 根據(jù)服務(wù)器返回的字節(jié)流的第3字節(jié)判斷服務(wù)器信息啄踊,并給服務(wù)器返回響應(yīng)數(shù)據(jù)忧设,告知服務(wù)器已接收到信息并停止發(fā)送重復(fù)數(shù)據(jù),否則服務(wù)器將持續(xù)不簡(jiǎn)單的發(fā)送數(shù)據(jù)
*/
if (responseBytes == 16) {
/**
* 字節(jié)流數(shù)據(jù)解析颠通,從第5個(gè)字節(jié)開(kāi)始解析
*/
// int responseLength;
// [data getBytes:&responseLength range:NSMakeRange(4, 1)];
// NSData *strData = [data subdataWithRange:NSMakeRange(5, responseLength)];
// NSString *string = [[NSString alloc] initWithData:strData encoding:NSUTF8StringEncoding];
// NSLog(@"response16 == %d, %@",responseLength, string);
NSMutableData *writer=[[NSMutableData alloc]init];
NSString *uuidStr = [SSKeychain passwordForService:@"com.ilincar.ilincar" account:@"ilincar"];
int version = 1;
int num = 1;
int cmd = 16;
int length = 0000;
//uuid 進(jìn)行MD5加密
NSData *UUIDData = [uuidStr dataUsingEncoding:NSUTF8StringEncoding];
Byte *byte = (Byte *)[UUIDData bytes];
Byte UUIDByte[16];
CC_MD5(byte, (int)UUIDData.length, UUIDByte);//md5 加密
[writer appendBytes:&version length:1];
[writer appendBytes:&num length:1];
[writer appendBytes:&cmd length:1];
[writer appendBytes:UUIDByte length:16];
[writer appendBytes:&length length:2];
[self.socket receiveWithTimeout:-1 tag:1];
[self.socket sendData:writer withTimeout:-1 tag:1];
} else if (responseBytes == 17) {
/**
* 字節(jié)流數(shù)據(jù)解析址晕,從第5個(gè)字節(jié)開(kāi)始解析
*/
// int responseLength;
// [data getBytes:&responseLength range:NSMakeRange(4, 1)];
// NSData *strData = [data subdataWithRange:NSMakeRange(5, responseLength)];
// NSString *string = [[NSString alloc] initWithData:strData encoding:NSUTF8StringEncoding];
// NSLog(@"response17 == %d, %@",responseLength, string);
NSMutableData *writer=[[NSMutableData alloc]init];
NSString *uuidStr = [SSKeychain passwordForService:@"com.ilincar.ilincar" account:@"ilincar"];
int version = 1;
int num = 1;
int cmd = 17;
int aaa = 0;
int bbb = 8;
//uuid 進(jìn)行MD5加密
NSData *UUIDData = [uuidStr dataUsingEncoding:NSUTF8StringEncoding];
Byte *byte = (Byte *)[UUIDData bytes];
Byte UUIDByte[16];
CC_MD5(byte, (int)UUIDData.length, UUIDByte);//md5 加密
//服務(wù)器所需的指定尾部字節(jié)需求
Byte *lastByte = (Byte *)[[data subdataWithRange:NSMakeRange(5, 8)] bytes];
[writer appendBytes:&version length:1];
[writer appendBytes:&num length:1];
[writer appendBytes:&cmd length:1];
[writer appendBytes:UUIDByte length:16];
[writer appendBytes:&aaa length:1];
[writer appendBytes:&bbb length:1];
[writer appendBytes:lastByte length:8];
[self.socket receiveWithTimeout:-1 tag:1];
[self.socket sendData:writer withTimeout:-1 tag:1];
} else if (responseBytes == 32) {
/**
* 字節(jié)流數(shù)據(jù)解析,從第5個(gè)字節(jié)開(kāi)始解析
*/
int responseLength;
[data getBytes:&responseLength range:NSMakeRange(4, 1)];//獲取所取范圍的字節(jié)流的長(zhǎng)度
NSData *strData = [data subdataWithRange:NSMakeRange(5, responseLength)];
NSString *string = [[NSString alloc] initWithData:strData encoding:NSUTF8StringEncoding];
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:strData options:NSJSONReadingMutableContainers error:nil];
// NSLog(@"UDPrespond32 = str:%@",string);
NSDictionary *orderDic = [dic valueForKey:@"order"];
NSString *code = [orderDic valueForKey:@"code"];
if ([code isEqualToString:@"003"]) {
NSUserDefaults *userDfaults = [NSUserDefaults standardUserDefaults];
[userDfaults removeObjectForKey:@"account"];
[userDfaults removeObjectForKey:@"bindState"];
[UIAppDelegate goToLoginView];
}
#pragma mark - 將結(jié)果回調(diào)給主頁(yè)面
if (self.receiveData != nil) {
self.receiveData(dic, string);
}
self.socketResult = [[NSDictionary alloc] initWithDictionary:dic];
NSMutableData *writer=[[NSMutableData alloc]init];
NSString *uuidStr = [SSKeychain passwordForService:@"com.ilincar.ilincar" account:@"ilincar"];
int version = 1;
int num = 1;
int cmd = 32;
int length = 0000;
//uuid 進(jìn)行MD5加密
NSData *UUIDData = [uuidStr dataUsingEncoding:NSUTF8StringEncoding];
Byte *byte = (Byte *)[UUIDData bytes];
Byte UUIDByte[16];
CC_MD5(byte, (int)UUIDData.length, UUIDByte);//md5加密
[writer appendBytes:&version length:1];
[writer appendBytes:&num length:1];
[writer appendBytes:&cmd length:1];
[writer appendBytes:UUIDByte length:16];
[writer appendBytes:&length length:2];
[self.socket receiveWithTimeout:-1 tag:1];
[self.socket sendData:writer withTimeout:-1 tag:1];
}
}
-(void)cutOffSocket {
[self.socket close];
}