利用GCDAsyncSocket实战经验

本篇文章的例子主要实现通过socket实时接收数据的一个图文直播的功能模块,代码为socket工具类。利用的工具是GCDAsyncSocket;


工具类主要有三个功能模块:

一、建立Socket连接,实现心跳连接,实现通过socket接收数据。

类名 Socket.h

二、数据处理模块,处理接收到的数据,避免粘包问题。

类名DataContro.h

三、断线重连模块,当socket断开时,重新启动一个新的socket请求,定时请求服务器,当连接成功时通知当前socket重新连接。

类名ReconnectControl.h


Socket类的创建方法如下:


    [Socket sharedInstance].socketHost = @"wei.fm.hebrbtv.com";// host设定
    [Socket sharedInstance].socketPort = 9004;// port设定
    // 在连接前先进行手动断开
    [Socket sharedInstance].socket.userData = SocketOfflineByUser;
    [[Socket sharedInstance] cutOffSocket];
    // 确保断开后再连,如果对一个正处于连接状态的socket进行连接,会出现崩溃
    [[Socket sharedInstance] socketConnectHost:^{
    }];
    [Socket sharedInstance].socket.userData = SocketOfflineByServer;
使用时需要添加几个通知方法

    //接收新消息通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(insertMessage:) name:SocketNewMessageNotification object:nil];
    //socket断开通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(socketConnectError) name:SocketConnectErrorNotification object:nil];
    //socket连接通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(socketConnectSuccess) name:SocketConnectSuccessNotification object:nil];

一、说一下Socket类里面的具体实现方法

连接方法

GCDAsyncSocket创建时需要添加一个线程 这里使用主线程,开启成功后即开启了一个通道,也可以理解为一个水管,后台通过这个通道不定时的发送数据过来。

// socket连接
-(void)socketConnectHost:(VoidBlock)block
{
    //数据处理类清楚历史数据
    [[DataControl shareControl] clearData];
    //回调方法
    _block = block;
    //连接socket
    self.socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
    NSError *error = nil;
    [self.socket connectToHost:self.socketHost onPort:self.socketPort withTimeout:3 error:&error];
}

连接成功后进行数据读取,开启心跳连接;之后会在GCDAsyncSocket的代理方法中获取后台发送的数据。

/**
 连接成功
 */
-(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
{
    if (_block) {
        _block();
    }
    //读取socket中的数据
    [self readData];
    // 每隔30s像服务器发送心跳包
    _connectTimer = [NSTimer scheduledTimerWithTimeInterval:30 target:self selector:@selector(longConnectToSocket) userInfo:nil repeats:YES];// 在longConnectToSocket方法中进行长连接需要向服务器发送的讯息
    [_connectTimer fire];
}
心跳连接:

// 心跳连接
-(void)longConnectToSocket{
    
    // 根据服务器要求发送固定格式的数据,假设为指令@".",但是一般不会是这么简单的指令
    NSString *longConnect = @".\n";
    NSData   *dataStream  = [longConnect dataUsingEncoding:NSUTF8StringEncoding];
    [self writeData:dataStream];
}
读取数据方法如下,这里加入了一个数据处理类,防止粘包现象,具体原理会在下面说明

/**
 收到服务器的数据,读取数据成功后通过SocketDataControl处理,防止粘包
 */
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
    [self readData];
    NSLog(@"读取成功");
    __block NSMutableArray *arr = [NSMutableArray new];
    [[DataControl shareControl] appendingData:data newData:^(NSMutableArray *models) {
        [self performSelector:@selector(sendMessage:) withObject:models];
        arr = models;
    }];
}

二、收处理模块:

  处理Socket数据粘包问题

三、断线重连模块

  Socket 断线重连问题

代码文件:

 代码文件


发布了93 篇原创文章 · 获赞 21 · 访问量 25万+
展开阅读全文

oc中,我用GCDAsyncSocket连上了socket,但是无法往服务器发送数据

01-04

#import "GCDSocketManager.h" #import "GCDAsyncSocket.h" #define SocketHost @"61.191.45.94" #define SocketPort 8091 @interface GCDSocketManager()<GCDAsyncSocketDelegate> //握手次数 @property(nonatomic,assign) NSInteger pushCount; //断开重连定时器 @property(nonatomic,strong) NSTimer *timer; //重连次数 @property(nonatomic,assign) NSInteger reconnectCount; @end @implementation GCDSocketManager //全局访问点 + (instancetype)sharedSocketManager { static GCDSocketManager *_instance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [[self alloc] init]; }); return _instance; } //可以在这里做一些初始化操作 - (instancetype)init { self == [super init]; if (self) { self.socket = [[GCDAsyncSocket alloc]initWithDelegate:self delegateQueue:dispatch_get_main_queue()]; } return self; } #pragma mark 请求连接 //连接 - (void)connectToServer { self.pushCount = 0; self.socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()]; NSError *error = nil; // [self.socket connectToHost:SocketHost onPort:SocketPort error:&error]; [self.socket connectToHost:SocketHost onPort:SocketPort error:&error]; if (error) { NSLog(@"SocketConnectError:%@",error); } } #pragma mark 连接成功 //连接成功的回调 - (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port { NSLog(@"socket连接成功"); [self sendDataToServer]; } //连接成功后向服务器发送数据 - (void)sendDataToServer { NSString *jsonData = @"kUOhLq1vFfPqzx5WtcJr0ZWmZ89uM9KEx4bthINy3HL2QD8oLjBGXhVv2gAlDjfwtTp0HrwnGLYxAloJ+ABzqzIS2OBG6MwDJLwQmJVPajgcNZhLZKFzmdvWbo+7HR+hSN2Co4DQRQfUm2n8HsDjAyNVUgpmO39NJ4XY085oGPE/dHkq/t5Y7A=="; NSData *cmdData = [jsonData dataUsingEncoding:NSUTF8StringEncoding]; NSLog(@"socket发送数据--->%@",cmdData); //发送 [self.socket writeData:cmdData withTimeout:-1 tag:0]; //读取数据 [self.socket readDataWithTimeout:-1 tag:100]; } //连接成功向服务器发送数据后,服务器会有响应 - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag { NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"收到的数据-->%@",msg); [self.socket readDataWithTimeout:-1 tag:200]; //服务器推送次数 self.pushCount++; //在这里进行校验操作,情况分为成功和失败两种,成功的操作一般都是拉取数据 } #pragma mark 连接失败 //连接失败的回调 - (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err { NSLog(@"Socket连接失败"); self.pushCount = 0; NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; NSString *currentStatu = [userDefaults valueForKey:@"Statu"]; //程序在前台才进行重连 if ([currentStatu isEqualToString:@"foreground"]) { //重连次数 self.reconnectCount++; //如果连接失败 累加1秒重新连接 减少服务器压力 NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 * self.reconnectCount target:self selector:@selector(reconnectServer) userInfo:nil repeats:NO]; self.timer = timer; } } //如果连接失败,5秒后重新连接 - (void)reconnectServer { self.pushCount = 0; self.reconnectCount = 0; //连接失败重新连接 NSError *error = nil; [self.socket connectToHost:SocketHost onPort:SocketPort error:&error]; if (error) { NSLog(@"SocektConnectError:%@",error); } } #pragma mark 断开连接 //切断连接 - (void)cutOffSocket { NSLog(@"socket断开连接"); self.pushCount = 0; self.reconnectCount = 0; [self.timer invalidate]; self.timer = nil; [self.socket disconnect]; } @end sendDataToServer中我调用writeData给服务器发送数据无法发送 问答

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览