iOS长连接Socket使用--AsyncSocket

本文介绍如何在iOS开发中使用AsyncSocket实现TCP长连接,包括单例类SocketTool的设计与实现,以及心跳包发送机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 SOCKET:TCP/IP网络的API。Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。Socket的出现只是使得程序员更方便地使用TCP/IP协议栈而已,是对TCP/IP协议的抽象,从而形成了我们知道的一些最基本的函数接口。

一般有不定时的向服务器传送数据的需求时,使用长连接, iOS开发中长连接的使用一般使用第三方库AsyncSocket, 对socket的封装比较好,使用起来很方便.

下载AsyncSocket    https://github.com/robbiehanson/CocoaAsyncSocket 

将RunLoop文件夹下的AsyncSocket.h, AsyncSocket.m, AsyncUdpSocket.h, AsyncUdpSocket.m 文件拷贝到自己的project中

添加 依赖库  CFNetwork.framework

1. 先创建一个单例类,命名SocketTool

SocketTool.h

//
//  SocketTool.h
//  SocketTest

#import <Foundation/Foundation.h>

@interface SocketTool : NSObject

+ (SocketTool *)shareInstance;

@end

SocketTool.m

#import "SocketTool.h"

@implementation SocketTool

+ (SocketTool *)shareInstance {
    
    static SocketTool *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

@end

2. 在SocketTool.h中导入

#import <sys/socket.h>
#import <netinet/in.h>
#import <arpa/inet.h>
#import <unistd.h>
#import "AsyncSocket.h"

声明变量

@property (nonatomic, strong) AsyncSocket *socket;
@property (nonatomic, copy) NSString *socketHost;
@property (nonatomic, assign) UInt16 socketPort; //端口号
@property (nonatomic, strong) NSTimer *connectTimer; // 计时器

声明连接和断开的方法

- (void)socketConnectHost; // socket连接

// 声明断开连接方法
- (void)cutOffSocket; // 断开socket连接.

代理

@interface SocketTool : NSObject<AsyncSocketDelegate>

枚举

enum {
    SocketOfflineByServer, // 服务器掉线, 默认为0.
    SocketOfflineByUser, //用户主动cut.
};

在SocketTool.m实现方法

//连接.
- (void)socketConnectHost {
    
    self.socket  = [[AsyncSocket alloc] initWithDelegate:self];
    NSError *error = nil;
    [self.socket connectToHost:self.socketHost onPort:self.socketPort withTimeout:30 error:&error];
}

//切断socket
- (void)cutOffSocket {
    
    self.socket.userData = SocketOfflineByUser; // 声明是由用户主动切断.
    [self.connectTimer invalidate];
    self.connectTimer = nil;
    [self.socket disconnect];
}

在SocketTool.m成功 和 失败的回调方法

#pragma mark ----------------------- 连接成功回调 --------------------------
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port {
    NSLog(@"连接成功");
    // 每隔30秒向服务器发送心跳包  一般设置30秒发送一次心跳包
    self.connectTimer = [NSTimer scheduledTimerWithTimeInterval:30 target:self selector:@selector(longConnectToSocket) userInfo:nil repeats:YES];
    [self.connectTimer fire];
}

//--------------------------------- will连接失败回调 -------------------------------
- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err {
    NSLog(@"连接失败");
}

//---------------------------------  连接失败回调 -------------------------------
// 重连
- (void)onSocketDidDisconnect:(AsyncSocket *)sock {
    NSLog(@"sorry the connect is failure %ld", sock.userData);
    if (sock.userData == SocketOfflineByServer) {
        //服务器掉线, 重连
        NSLog(@"服务器掉线**********请重新连接");
        [self socketConnectHost];
    } else if (sock.userData == SocketOfflineByUser) {
        // 如果用户断开, 不进行重连.
        return;
    }
}

得到服务器下发消息会调用的方法

// 如果得到数据, 就会调用回调方法.
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
    NSLog(@"长连接下发的消息*****************%@",data);
    // 对得到的data值进行解析与转换即可.

}

心跳连接方法

// 心跳连接
- (void)longConnectToSocket {
    // 根据服务器要求发送固定格式的数据, 假设为指令@"longConnect", 但是一般不会是这么简单地指令.
    NSLog(@"我发送了一次心跳包");
    NSString *longConnect = @"longConnect";
    NSData *dataStream = [longConnect dataUsingEncoding:NSUTF8StringEncoding];
    
    [self.socket writeData:dataStream withTimeout:1 tag:1];
    
    
}

至此连接类已经完成

使用

导入#import "SocketTool.h"

[SocketTool shareInstance].socketHost = @"<code class="hljs actionscript"><span class="hljs-string"><span class="hljs-string">192.186.100.21</span></span></code>";// host设定
[SocketTool shareInstance].socketPort = 8282;// port设定
    
// 在连接前先进行手动断开
[SocketTool shareInstance].socket.userData = SocketOfflineByUser;
[[SocketTool shareInstance] cutOffSocket];
    
// 确保断开后再连,如果对一个正处于连接状态的socket进行连接,会出现崩溃
[SocketTool shareInstance].socket.userData = SocketOfflineByServer;
[[SocketTool shareInstance] socketConnectHost];



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值