IOS-群聊天服务端以及客户端的心跳包(三)

群聊思路:客户端ABC都连接到服务器,当客户端A发送信息给服务器,服务端把A的信息发送给除A以外的B、C客户端

在这的基础上IOS-基于CocoaAsyncSocket的服务端的监听(二),
服务器方面:唯一变化的就是在服务端读取客户端请求数据的时候要做判断

#pragma mark 服务端读取客户端请求数据
- (void)socket:(GCDAsyncSocket *)clientSocket didReadData:(NSData *)data withTag:(long)tag{
    NSLog(@"clientSocket读取保存在severSocket的clientSocket数据:%@",clientSocket);
    
    //1、NSData转成string
    NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
  
    //2、群聊服务:把当前客户端的数据转发给其他客户端,ABC客户端都连接了服务端,A客户端发送消息给服务端,服务端要遍历存在服务端的客户端数据,把除了A客户端发送的消息转发给BC。这样可以构成一个群聊的服务
    NSLog(@"接受到客户端上传的数据responseStr:%@",str);
    //3、处理请求,返回数据给客户端
    for (GCDAsyncSocket *socket in self.clientSockets) {
        if (socket == clientSocket) {
            //是自己A 不发送
        }else{
            //是BC 把存在服务端的A消息发送给BC
            [socket writeData:data withTimeout:-1 tag:0];

        }
    }
#warning 只会读取1次 每次读完数据都要监听
    [clientSocket readDataWithTimeout:-1 tag:0];
}

客户端方面
1、实现socket以及发送消息

- (void)viewDidLoad {
    [super viewDidLoad];

    //实现聊天室雏形
    //1.连接到群聊服务器
    //1.1.创建客户端socket对象
    self.clientSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(0, 0)];
    //1.2.发送连接请求
    NSError *error;
    [self.clientSocket connectToHost:@"192.168.1.75" onPort:5288 error:&error];
    if (!error) {
        NSLog(@"%@",error);
    }
}

2、socket代理判断是否连接成功

#pragma mark socket连接成功
- (void)socket:(GCDAsyncSocket *)clientSocket didConnectToHost:(NSString *)host port:(uint16_t)port{
    NSLog(@"与服务器连接成功");
    //客户端监听读取数据
    [clientSocket readDataWithTimeout:-1 tag:0];
}
#pragma mark socket连接失败
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err{
    NSLog(@"与服务器断开连接%@",err);

    self.clientSocket = nil;
    self.clientSocket.delegate = nil;
}

3、读取服务端返回的数据

#pragma mark 读取消息,socket客户端监听数据
- (void)socket:(GCDAsyncSocket *)clientSocket didReadData:(NSData *)data withTag:(long)tag{
    NSLog(@"读取消息");
    NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"%@读取消息",str);
    /*添加消息
    if (str) {
        [self.dataSource addObject:str];
#warning 要在主线程
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            [self.tableView reloadData];
        }];
    }*/
#warning 读完数据继续监听。// withTimeout -1 : 无穷大,一直等
    [clientSocket readDataWithTimeout:-1 tag:0];
}

4、创建一个Btn手动发送消息

#pragma mark 手动发送
- (IBAction)send:(id)sender {
    NSString *str = @"11";
    if (str.length ==0 ) {//无数据
        return;
    }
 /*   [self.dataSource addObject:str];
//    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        [self.tableView reloadData];
//    }];*/
    //发送数据
    [self.clientSocket writeData:[str dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:0];
}

当然也可以定时发送,就是所谓的心跳包,每次间隔几秒给服务器发送一条双方协商好的固定格式,如果粘包,那就在固定格式末尾加上某个特定符号,让服务端监听特定符号是否接受成功。因为在某些特殊情况下,包的发送数据过大可能会发n次。

#pragma mark 心跳发送
// 添加定时器
- (void)addTimer
{
    // 长连接定时器
    self.connectTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(longConnectToSocket) userInfo:nil repeats:YES];
    // 把定时器添加到当前运行循环,并且调为通用模式
    [[NSRunLoop currentRunLoop] addTimer:self.connectTimer forMode:NSRunLoopCommonModes];
}
// 心跳连接
- (void)longConnectToSocket
{
    // 发送固定格式的数据,指令@"longConnect",这里要和服务器有固定的格式
    float version = [[UIDevice currentDevice] systemVersion].floatValue;
    NSString *longConnect = [NSString stringWithFormat:@"ping%f",version];
    
    NSData  *data = [longConnect dataUsingEncoding:NSUTF8StringEncoding];
    
    //发送心跳包
    [self.clientSocket writeData:data withTimeout:- 1 tag:0];
}

你可能感兴趣的:(IOS-群聊天服务端以及客户端的心跳包(三))