当前位置: 移动技术网 > IT编程>移动开发>IOS > iOS应用中使用AsyncSocket库处理Socket通信的用法讲解

iOS应用中使用AsyncSocket库处理Socket通信的用法讲解

2019年07月24日  | 移动技术网IT编程  | 我要评论

膨胀螺栓型号,深海之战下载,牛烽网

用socket可以实现像qq那样发送即时消息的功能。客户端和服务端需要建立长连接,在长连接的情况下,发送消息。客户端可以发送心跳包来检测长连接。

在ios开发中使用socket,一般都是用第三方库asyncsocket,不得不承认这个库确实很强大。下载地址cocoaasyncsocket

特性

asyncsocket类是支持tcp的。
asyncudpsocket是支持udp的。
asyncsocket是封装了cfsocket和cfsteam的tcp/ip socket网络库。它提供了异步操作,本地cocoa类的基于delegate的完整支持。主要有以下特性:

  • 队列的非阻塞的读和写,而且可选超时。你可以调用它读取和写入,它会当完成后告知你。
  • 自动的socket接收。如果你调用它接收连接,它将为每个连接启动新的实例,当然,也可以立即关闭这些连接。
  • 委托(delegate)支持。错误、连接、接收、完整的读取、完整的写入、进度以及断开连接,都可以通过委托模式调用。
  • 基于run loop的,而不是线程的。虽然可以在主线程或者工作线程中使用它,但你不需要这样做。它异步的调用委托方法,使用nsrunloop。委托方法包括socket的参数,可让你在多个实例中区分。
  • 自包含在一个类中。你无需操作流或者socket,这个类帮你做了全部。
  • 支持基于ipv4和ipv6的tcp流。

asyncudpsocket是udp/ip socket网络库,包装自cfsocket。它的工作很像tcp版本,只不过是用于处理udp的。它包括基于非阻塞队列的发送接收操作,完整的委托支持,基于runloop,自包含的类,以及支持ipv4和ipv6。

使用asyncsocket的时候可以做一层封装,根据需求提供几个接口出来。比如:连接、断开连接、发送消息等等。还有接受消息,接受到的消息可以通过通知、代理、block等传出去。

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

定义单列类:lgsocketserve

lgsocketserve.h

复制代码 代码如下:

//
//  lgsocketserve.h
//  asyncsocketdemo
//

#import <foundation/foundation.h>
#import "asyncsocket.h"

@interface lgsocketserve : nsobject<asyncsocketdelegate>

+ (lgsocketserve *)sharedsocketserve;


@end


lgsocketserve.m
复制代码 代码如下:

//
//  lgsocketserve.m
//  asyncsocketdemo
//

#import "lgsocketserve.h"

@implementation lgsocketserve


static lgsocketserve *socketserve = nil;

#pragma mark public static methods


+ (lgsocketserve *)sharedsocketserve {
    @synchronized(self) {
        if(socketserve == nil) {
            socketserve = [[[self class] alloc] init];
        }
    }
    return socketserve;
}


+(id)allocwithzone:(nszone *)zone
{
    @synchronized(self)
    {
        if (socketserve == nil)
        {
            socketserve = [super allocwithzone:zone];
            return socketserve;
        }
    }
    return nil;
}  


@end


建立socket长连接

lgsocketserve.h

复制代码 代码如下:

@property (nonatomic, strong) asyncsocket         *socket;       // socket

//  socket连接
- (void)startconnectsocket;
lgsocketserve.m

//自己设定
#define host @"192.168.0.1"
#define port 8080

//设置连接超时
#define time_out 20

- (void)startconnectsocket
{
    self.socket = [[asyncsocket alloc] initwithdelegate:self];
    [self.socket setrunloopmodes:[nsarray arraywithobject:nsrunloopcommonmodes]];
    if ( ![self socketopen:host port:port] )
    {

    }

}

- (nsinteger)socketopen:(nsstring*)addr port:(nsinteger)port
{

    if (![self.socket isconnected])
    {
        nserror *error = nil;
        [self.socket connecttohost:addr onport:port withtimeout:time_out error:&error];
    }

    return 0;
}


宏定义一下host、port、time_out,实现startconnectsocket方法。这个时候要设置一下asyncsocket的代理asyncsocketdelegate。当长连接成功之后会调用:
复制代码 代码如下:

- (void)onsocket:(asyncsocket *)sock didconnecttohost:(nsstring *)host port:(uint16)port
{
    //这是异步返回的连接成功,
    nslog(@"didconnecttohost");
}

心跳

lgsocketserve.h

复制代码 代码如下:

@property (nonatomic, retain) nstimer             *hearttimer;   // 心跳计时器
lgsocketserve.m

- (void)onsocket:(asyncsocket *)sock didconnecttohost:(nsstring *)host port:(uint16)port
{
    //这是异步返回的连接成功,
    nslog(@"didconnecttohost");

    //通过定时器不断发送消息,来检测长连接
    self.hearttimer = [nstimer scheduledtimerwithtimeinterval:2 target:self selector:@selector(checklongconnectbyserve) userinfo:nil repeats:yes];
    [self.hearttimer fire];
}

// 心跳连接
-(void)checklongconnectbyserve{

    // 向服务器发送固定可是的消息,来检测长连接
    nsstring *longconnect = @"connect is here";
    nsdata   *data  = [longconnect datausingencoding:nsutf8stringencoding];
    [self.socket writedata:data withtimeout:1 tag:1];
}


在连接成功的回调方法里,启动定时器,每隔2秒向服务器发送固定的消息来检测长连接。(这个根据服务器的需要就可以了)

断开连接

1,用户手动断开连接

lgsocketserve.h

复制代码 代码如下:

// 断开socket连接
-(void)cutoffsocket;
lgsocketserve.m

-(void)cutoffsocket
{
    self.socket.userdata = socketofflinebyuser;
    [self.socket disconnect];
}


cutoffsocket是用户断开连接之后,不在尝试重新连接。

2,wifi断开,socket断开连接

lgsocketserve.m

复制代码 代码如下:

- (void)onsocket:(asyncsocket *)sock willdisconnectwitherror:(nserror *)err
{

    nslog(@" willdisconnectwitherror %ld   err = %@",sock.userdata,[err description]);
    if (err.code == 57) {
        self.socket.userdata = socketofflinebywificut;
    }

}


wifi断开之后,会回调onsocket:willdisconnectwitherror:方法,err.code == 57,这个时候设置self.socket.userdata = socketofflinebywificut。

重新连接

socket断开之后会回调:

lgsocketserve.m

复制代码 代码如下:

- (void)onsocketdiddisconnect:(asyncsocket *)sock
{

    nslog(@"7878 sorry the connect is failure %ld",sock.userdata);

    if (sock.userdata == socketofflinebyserver) {
        // 服务器掉线,重连
        [self startconnectsocket];
    }
    else if (sock.userdata == socketofflinebyuser) {

        // 如果由用户断开,不进行重连
        return;
    }else if (sock.userdata == socketofflinebywificut) {

        // wifi断开,不进行重连
        return;
    }

}


在onsocketdiddisconnect回调方法里面,会根据self.socket.userdata来判断是否需要重新连接。

发送消息

lgsocketserve.h

复制代码 代码如下:

// 发送消息
- (void)sendmessage:(id)message;
lgsocketserve.m

//设置写入超时 -1 表示不会使用超时
#define write_time_out -1

- (void)sendmessage:(id)message
{
    //像服务器发送数据
    nsdata *cmddata = [message datausingencoding:nsutf8stringencoding];
    [self.socket writedata:cmddata withtimeout:write_time_out tag:1];
}

//发送消息成功之后回调
- (void)onsocket:(asyncsocket *)sock didwritedatawithtag:(long)tag
{

}


发送消息成功之后会调用onsocket:didwritedatawithtag:,在这个方法里可以进行读取消息。

接受消息

lgsocketserve.m

复制代码 代码如下:

//设置读取超时 -1 表示不会使用超时
#define read_time_out -1

#define max_buffer 1024

//发送消息成功之后回调
- (void)onsocket:(asyncsocket *)sock didwritedatawithtag:(long)tag
{
    //读取消息
    [self.socket readdatawithtimeout:-1 buffer:nil bufferoffset:0 maxlength: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:read_time_out buffer:nil bufferoffset:0 maxlength:max_buffer tag:0];


接受消息后去解析,然后可以通过通知、代理、block等传出去。在onsocket:didreaddata:withtag:回调方法里面需要不断读取消息,因为数据量比较大的话,服务器会分多次返回。所以我们需要定义一个max_buffer的宏,表示每次最多读取多少。当data.length < max_buffer我们认为有可能是接受完一个完整的消息,然后才解析 。

出错处理

lgsocketserve.m

复制代码 代码如下:

- (void)onsocket:(asyncsocket *)sock willdisconnectwitherror:(nserror *)err
{
    nsdata * unreaddata = [sock unreaddata]; // ** this gets the current buffer
    if(unreaddata.length > 0) {
        [self onsocket:sock didreaddata:unreaddata withtag:0]; // ** return as much data that could be collected
    } else {

        nslog(@" willdisconnectwitherror %ld   err = %@",sock.userdata,[err description]);
        if (err.code == 57) {
            self.socket.userdata = socketofflinebywificut;
        }
    }

}


socket出错会回调onsocket:willdisconnectwitherror:方法,可以通过unreaddata来读取未来得及读取的buffer。

使用

导入#import “lgsocketserve.h”

复制代码 代码如下:

 lgsocketserve *socketserve = [lgsocketserve sharedsocketserve];
//socket连接前先断开连接以免之前socket连接没有断开导致闪退
[socketserve cutoffsocket];
socketserve.socket.userdata = socketofflinebyserver;
[socketserve startconnectsocket];

//发送消息 @"hello world"只是举个列子,具体根据服务端的消息格式
[socketserve sendmessage:@"hello world"];

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

  • ios uicollectionview实现横向滚动

    现在使用卡片效果的app很多,之前公司让实现一种卡片效果,就写了一篇关于实现卡片的文章。文章最后附有demo实现上我选择了使用uicollectionview ... [阅读全文]
  • iOS UICollectionView实现横向滑动

    本文实例为大家分享了ios uicollectionview实现横向滑动的具体代码,供大家参考,具体内容如下uicollectionview的横向滚动,目前我使... [阅读全文]
  • iOS13适配深色模式(Dark Mode)的实现

    iOS13适配深色模式(Dark Mode)的实现

    好像大概也许是一年前, mac os系统发布了深色模式外观, 看着挺刺激, 时至今日用着也还挺爽的终于, 随着iphone11等新手机的发售, ios 13系统... [阅读全文]
  • ios 使用xcode11 新建项目工程的步骤详解

    ios 使用xcode11 新建项目工程的步骤详解

    xcode11新建项目工程,新增了scenedelegate这个类,转而将原appdelegate负责的对ui生命周期的处理担子接了过来。故此可以理解为:ios... [阅读全文]
  • iOS实现转盘效果

    本文实例为大家分享了ios实现转盘效果的具体代码,供大家参考,具体内容如下demo下载地址: ios转盘效果功能:实现了常用的ios转盘效果,轮盘抽奖效果的实现... [阅读全文]
  • iOS开发实现转盘功能

    本文实例为大家分享了ios实现转盘功能的具体代码,供大家参考,具体内容如下今天给同学们讲解一下一个转盘选号的功能,直接上代码直接看viewcontroller#... [阅读全文]
  • iOS实现轮盘动态效果

    本文实例为大家分享了ios实现轮盘动态效果的具体代码,供大家参考,具体内容如下一个常用的绘图,主要用来打分之类的动画,效果如下。主要是ios的绘图和动画,本来想... [阅读全文]
  • iOS实现九宫格连线手势解锁

    本文实例为大家分享了ios实现九宫格连线手势解锁的具体代码,供大家参考,具体内容如下demo下载地址:效果图:核心代码://// clockview.m// 手... [阅读全文]
  • iOS实现卡片堆叠效果

    本文实例为大家分享了ios实现卡片堆叠效果的具体代码,供大家参考,具体内容如下如图,这就是最终效果。去年安卓5.0发布的时候,当我看到安卓全新的material... [阅读全文]
  • iOS利用余弦函数实现卡片浏览工具

    iOS利用余弦函数实现卡片浏览工具

    本文实例为大家分享了ios利用余弦函数实现卡片浏览工具的具体代码,供大家参考,具体内容如下一、实现效果通过拖拽屏幕实现卡片移动,左右两侧的卡片随着拖动变小,中间... [阅读全文]
验证码:
移动技术网