您的位置:首页 > 移动开发 > IOS开发

iOS开发之AsyncSocket使用

2016-02-23 15:17 513 查看
用socket可以实现像QQ那样发送即时消息的功能。客户端和服务端需要建立长连接,在长连接的情况下,发送消息。客户端可以发送心跳包来检测长连接。

简单介绍一下对AsyncSocket使用.一般来说,一个用户只需要建立一个socket长连接,所以可以用单例类方便使用。

.h
enum{
SocketOfflineByServer,      //服务器掉线
SocketOfflineByUser,        //用户断开
SocketOfflineByWifiCut,     //wifi 断开
};

+ (SocketServeModle *)sharedSocketServe;
@property (nonatomic, strong) AsyncSocket *socket;
// socket 连接
- (void)startConnectSocket;
#pragma mark - heart jump
@property (nonatomic, retain) NSTimer *heartTmier;
// socket 断开
- (void)cutOffSocket;
// 发送消息
- (void)sendMessage:(id)message;


.m
#define HOST_NAME @"192.168.0.1"
#define PORT 8080
// Connect time out
#define TIME_OUT 20
//
#define MAX_BUFFER 1024


+(SocketServeModle *)sharedSocketServe
{
// Create a singleton
static SocketServeModle *socketServe = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
socketServe = [[SocketServeModle alloc] init];
});
return socketServe;
}


#pragma mark -
- (void)startConnectSocket
{
self.socket = [[AsyncSocket alloc] initWithDelegate:self];
[self.socket setRunLoopModes:[NSArray arrayWithObject:NSRunLoopCommonModes]];
if (![self socketOpen:HOST_NAME port:PORT]) {

}
}


#pragma mark -
- (NSInteger)socketOpen:(NSString *)address port:(NSInteger)port
{
// if Connect not - fail
if (![self.socket isConnected]) {
NSError *error = nil;
[self.socket connectToHost:address onPort:port error:&error];
}
return 0;
}


#pragma mark -
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
// it is asyn
NSLog(@"didConnectToHost");

// 通过定时器不断的发送消息, 来检测长连接 By the timer sends a message to detect long connection
self.heartTmier = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(checkLongConnectByServe) userInfo:nil repeats:YES];
[self.heartTmier fire];

}


#pragma mark - checkLongConnectByServe
- (void)checkLongConnectByServe
{
// 向服务器发送固定的消息, 来检测长连接
NSString *longConnect = @"connect is success";
NSData *data = [longConnect dataUsingEncoding:NSUTF8StringEncoding];
[self.socket writeData:data withTimeout:1 tag:1];
}


#pragma mark - 断开
- (void)cutOffSocket
{
self.socket.userData = SocketOfflineByUser;
[self.socket disconnect];
}


#pragma mark - 出错处理
- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err
{
if (err.code == 57) {
self.socket.userData = SocketOfflineByWifiCut;
}
NSData *unreadData = [sock unreadData];

if (unreadData.length > 0) {
[self onSocket:sock didReadData:unreadData withTag:0];
}else{
self.socket.userData = SocketOfflineByWifiCut;
}

}


#pragma mark - 回调
- (void)onSocketDidDisconnect:(AsyncSocket *)sock
{
if (sock.userData == SocketOfflineByServer) {
// 服务器掉线, 重连
[self startConnectSocket];
}else if (sock.userData == SocketOfflineByUser){
// 如果由用户断开, 不进行重连
return;
}else if (sock.userData == SocketOfflineByWifiCut){
// wifi断开
return;
}
}


#pragma mark -
- (void)sendMessage:(id)message
{
// 向服务器发送数据
NSData *data = [message dataUsingEncoding:NSUTF8StringEncoding];
// -1 表示不会使用超时
[self.socket writeData:data withTimeout:-1 tag:1];
}


#pragma mark -
- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
{
// 消息成功的回调
// 读取消息
[self.socket readDataWithTimeout:-1 buffer:nil bufferOffset:MAX_BUFFER tag:0];

}


- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
// 服务器返回的消息数据量比较大时, 可以分多次返回, 所以在读取消息的时候,设置MAX_BUFFER表示每次最多读取多少,当data.length < MAX_BUFFER我们认为有可能是接受完一个完整的消息,然后才解析

if (data.length < MAX_BUFFER) {
// 结果的解析
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
NSLog(@"%@", dic);
// 解析出来的消息, 可以通过通知, 代理, block传出去

}
[self.socket readDataWithTimeout:-1 buffer:nil bufferOffset:MAX_BUFFER tag:0];
}


简单使用

SocketServeModle *serve = [SocketServeModle sharedSocketServe];
// 连接之前先断开
[serve cutOffSocket];
serve.socket.userData = SocketOfflineByServer;
[serve startConnectSocket];


参照原文链接http://www.superqq.com/blog/2015/04/03/ioskai-fa-zhi-asyncsocketshi-yong-jiao-cheng/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: