(六十五)iOS的socket实现(GCDAsyncSocket)

本文介绍使用GCDAsyncSocket来实现iOS端的socket,有关简易服务端的代码已经在上一篇文章中提到,这里不再赘述,将直接介绍如何实现客户端。

首先下载CocoaAsyncSocket框架,如果下载过iOS的XMPP框架,在Vendor中有这个框架,将框架导入工程,并包含其头文件GCDAsyncSocket.h。

①这是一个异步socket框架,在子线程中完成socket的连接和数据接收,通过代理的方式通知控制器,因此要成为它的代理,代理名为GCDAsyncSocketDelegate。

②创建GCDAsyncSocket对象,并且使之成为成员属性,该对象兼备了输入输出流的功能,后续需要使用。

GCDAsyncSocket *_socket;

我们在这里传入一个全局队列,让它工作在子线程,防止网络不畅时阻塞主线程。

_socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];

③连接服务端,还是假设服务端在本地,端口为12345,使用socket的connectToHost方法连接:
    NSString *host = @"127.0.0.1";
    int port = 12345;
    NSError *error = nil;
    [_socket connectToHost:host onPort:port error:&error];
    if (error) {
        NSLog(@"%@",error);
    }
④实现代理方法来获取数据:

4.1连接成功的代理:

-(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port{
    
    NSLog(@"成功连接到%@:%d",host,port);
    
}

4.2连接结束的代理:

- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err{
    if (err) {
        NSLog(@"%@",err);
    }
}

4.3接收数据的代理

特别注意此处,只有先在发送成功的代理中调用读取方法,才会调用读取的代理方法:

这里的tag是用于区分不同的消息的,在写一条消息的时候需要指定tag,通过不同的tag判断服务器返回的消息的类型。这里有两类消息,分别是登录消息和聊天消息,只有后者会被显示,reloadDataWithText是用于tableView显示数据的方法。

这里对数据处理起来很简单,只需要把data直接转化为NSString即可。

// 数据成功发送到服务器
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag{
    
    // 需要自己调用读取方法,socket才会调用代理方法读取数据
    [_socket readDataWithTimeout:-1 tag:tag];
    
}
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{
    
    switch (tag) {
        case LoginTag:     
            break;
        case MsgTag:{
            NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            [self reloadDataWithText:msg];
            break;
        }
        default:
            break;
    }
       
}

⑤发送一条消息:

使用socket的writeData方法,这里不需要指定消息的长度和缓冲区大小,十分方便,tag会被传入,在调用上面提到的代理方法(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag时会被传入,用于判断消息类型。

    // 发送 iam:name 表示name登录
    NSString *loginStr = @"iam:soulghost";
    // 把string转成NSData
    NSData *data = [loginStr dataUsingEncoding:NSUTF8StringEncoding];
    [_socket writeData:data withTimeout:-1 tag:LoginTag];

需要注意的是异步socket工作在子线程,如果要更新UI,必然会在socket的代理方法中调用更新UI的方法,这时更新UI的代码运行于子线程,不能立即刷新UI界面,因此应该把更新UI的函数放在主线程中执行:

    dispatch_async(dispatch_get_main_queue(), ^{
        // 更新UI的代码
    });




转载于:https://www.cnblogs.com/aiwz/p/6154153.html

发布了0 篇原创文章 · 获赞 12 · 访问量 6万+
展开阅读全文
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符

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官方博客

分享到微信朋友圈

×

扫一扫,手机浏览