局域网内端到端的聊天项目(五)

效果图:
iPod.gif
iPhone.gif
  • 上一篇已实现单张图片的相互传输
  • 接下来实现多张图片的传输
1.图片的来源及传输方式不变
2.当接收方收到的是媒体文件时 需要把媒体文件流写入磁盘后 在发送一个特定指令到发送方 这样就不会造成错乱 (ps:传输失败还需在考虑)
3.发送方在接收到特定指令后会去循环缓存集合,发送第一个缓存消息体
4.最终的传输方式还是一条一条的传输
一.图片选择后发送的方法不变
- (void)sendImageOrVideo{
    WS(weakSelf);
    [[PickerImageVideoTool sharePickerImageVideoTool] showImagePickerWithMaxCount:9 completion:^(NSArray *photos, NSArray *assets) {
        NSInteger count = assets.count;
        id objc = nil;
        for (NSInteger i = 0; i < count; i++) {
            objc = assets[i];
            if (![objc isKindOfClass:[PHAsset class]]) {
                continue;
            }
            PHAsset *asset = (PHAsset *)objc;
            ChatMessageModel *messageM = [ChatMessageModel new];
            messageM.isFormMe = YES;
            messageM.userName = [UIDevice currentDevice].name;
            messageM.asset = asset;
            messageM.fileName = [ZPPublicMethod getAssetsName:asset only:YES];
            messageM.temImage = photos[i];
            if (asset.mediaType == PHAssetMediaTypeImage){
                messageM.chatMessageType = ChatMessageImage;
                messageM.fileSize = UIImagePNGRepresentation(messageM.temImage).length;
                SDImageCache *cache = [SDImageCache sharedImageCache];
                [cache storeImage:messageM.temImage forKey:messageM.fileName toDisk:YES completion:^{
                    messageM.mediaMessageUrl = [NSURL fileURLWithPath:[cache defaultCachePathForKey:messageM.fileName]];
                }];
                [weakSelf sendMessageWithItem:messageM];
            }else if (asset.mediaType == PHAssetMediaTypeAudio){
                messageM.chatMessageType = ChatMessageAudio;
            }else if (asset.mediaType == PHAssetMediaTypeVideo) {
                messageM.chatMessageType = ChatMessageVideo;
            }
        }
    }];
}

// 发送消息体
- (void)sendMessageWithItem:(ChatMessageModel *)item{
    item.locationIndex = self.messageItems.count;
    [self.messageItems addObject:item];
    [self.tableView reloadData];
    SocketManager *manager = [SocketManager shareSockManager];
    [manager sendMessageWithItem:item];
}
二.SocketManager 类中新增一个缓存用的数组
/// 当有多个需要发送时
@property (nonatomic, strong) NSMutableArray *needSendMoreItems;
外界传入需要发送的 item
  • 判断当前缓存数组个数>=2个 如果是就缓存下一条需要发送的消息
/// 发送数据
- (void)sendMessageWithItem:(ChatMessageModel *)item{
    item.atSendArrayIndex = self.needSendMoreItems.count;
    [self.needSendMoreItems addObject:item];
    if (self.needSendMoreItems.count < 2) {
        [self sendOneMessageItem:item];
    }else{
        
    }
}

- (void)sendOneMessageItem:(ChatMessageModel *)item{
    self.currentSendItem = item;
    NSData *textData = [self creationMessageDataWithItem:item];
    [self writeMediaMessageWithData:textData];
}

// 创建消息体
- (NSData *)creationMessageDataWithItem:(ChatMessageModel *)item{
    NSMutableDictionary *messageData = [NSMutableDictionary dictionary];
    messageData[@"fileName"] = item.fileName;
    messageData[@"userName"] = item.userName;
    messageData[@"chatMessageType"] = [NSNumber numberWithInt:item.chatMessageType];
    messageData[@"fileSize"] = [NSNumber numberWithInteger:item.fileSize];
    if (item.chatMessageType == ChatMessageText) {
        messageData[@"messageContent"] = item.messageContent;
    }else if (item.chatMessageType == ChatMessageImage){
        item.isWaitAcceptFile = YES;
        messageData[@"isWaitAcceptFile"] = [NSNumber numberWithBool:YES];
    }
    NSString *bodStr = [NSString hj_dicToJsonStr:messageData];
    return [bodStr dataUsingEncoding:NSUTF8StringEncoding];
}

// 图片或者视频文件传输
- (void)imageOrVideoFileSend:(ChatMessageModel *)sendItem{
    if (sendItem.chatMessageType == ChatMessageImage) {
        NSData *sendData = UIImagePNGRepresentation(sendItem.temImage);
        [self writeMediaMessageWithData:sendData];
    }else if (sendItem.chatMessageType == ChatMessageVideo){
       // 视频预留
    }
    
}

// 传输数据到服务端
- (void)writeMediaMessageWithData:(NSData *)sendData{
    self.currentSendTag += 1;
    self.currentSendItem.sendTag = self.currentSendTag;
    if (self.clientSocketArray.count > 0) {
        GCDAsyncSocket *clientSocket = [self.clientSocketArray firstObject];
        [clientSocket writeData:sendData withTimeout:-1 tag:self.currentSendItem.sendTag];
    }else{
        [self.tcpSocketManager writeData:sendData withTimeout:-1 tag:self.currentSendItem.sendTag];
    }
}

// 媒体文件接受完成后发送的消息
- (void)sendMediaAcceptEndMessage{
    NSData *data = [FILE_ACCEPT_END dataUsingEncoding:NSUTF8StringEncoding];
    [self writeMediaMessageWithData:data];
}

// 发送下一个消息体
- (void)sendNextMessage{
    if (self.needSendMoreItems.count > 0) {
        [self sendOneMessageItem:[self.needSendMoreItems firstObject]];
    }
}

当前消息发送完毕后的回调处理
  • 发送图片的策略是通过先发送一个信息头给对方 isWaitAcceptFile 字段为 YES
  • 头部发送完毕后在发送图片
  • 当前消息体全部发送完成后(如果是图片包括头部+图片)从缓存数组中移除该消息体,在判断缓存数组中是否还有需要发送的消息体
  • 当头部发送完毕后需延时发送文件
/// 接收到消息
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{
    [sock readDataWithTimeout:- 1 tag:0];
    
    NSString *readStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSDictionary *readDic = [readStr hj_jsonStringToDic];
    
    if ([readStr isEqualToString:FILE_ACCEPT_END]) {
        [self sendNextMessage];
        return;
    }else if ([readDic isKindOfClass:[NSDictionary class]]) {
        MYLog(@"readDic = %@",readDic);
        self.acceptItem = [ChatMessageModel mj_objectWithKeyValues:readDic];
        self.acceptItem.isFormMe = NO;
        self.acceptItem.finishAccept = self.acceptItem.chatMessageType != ChatMessageText ? NO : YES;
    }else if (self.acceptItem.isWaitAcceptFile) {
        self.acceptItem.finishAccept = NO;
        self.acceptItem.acceptSize += data.length;
        self.acceptItem.beginAccept = YES;
        if (!self.outputStream) {
            self.acceptItem.acceptFilePath = [self.dataSavePath stringByAppendingPathComponent:[self.acceptItem.fileName lastPathComponent]];
            self.acceptItem.mediaMessageUrl = [NSURL fileURLWithPath:self.acceptItem.acceptFilePath];
self.acceptItem.showImageUrl = self.acceptItem.chatMessageType == ChatMessageImage ? self.acceptItem.mediaMessageUrl : nil;
            self.outputStream = [[NSOutputStream alloc] initToFileAtPath:self.acceptItem.acceptFilePath append:YES];
            [self.outputStream open];
        }
        // 输出流 写数据
        NSInteger byt = [self.outputStream write:data.bytes maxLength:data.length];
        MYLog(@"byt = %zd totalSize = %zd",byt,self.acceptItem.fileSize);
        if (self.acceptItem.acceptSize >= self.acceptItem.fileSize) {
            self.acceptItem.finishAccept = YES;
            [self.outputStream close];
            self.outputStream = nil;
            [self sendMediaAcceptEndMessage];
        }
    }else{
        
    }
    if ([self.delegate respondsToSelector:@selector(socketManager:itemAcceptingrefresh:)]) {
        [self.delegate socketManager:self itemAcceptingrefresh:self.acceptItem];
    }
  
}

// 文件传输完毕后的回调
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag{
    MYLog(@"%s \n tag = %ld",__func__,tag);
    if (self.currentSendItem.sendTag == tag) {
        if (!self.currentSendItem.isWaitAcceptFile) {
            self.currentSendItem.temImage = nil;
            self.currentSendItem.sendSuccess = YES;
            self.currentSendItem.isSendFinish = YES;
            self.currentSendItem.isSending = NO;
            if ([self.delegate respondsToSelector:@selector(socketManager:itemUpFinishrefresh:)]) {
                [self.delegate socketManager:self itemUpFinishrefresh:self.currentSendItem];
            }
            // 缓存数组
            [self.needSendMoreItems removeObject:self.currentSendItem];
        }else{
           // 接下来需要传输文件
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.8 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                self.currentSendItem.isWaitAcceptFile = NO; // 改变状态
                [self imageOrVideoFileSend:self.currentSendItem];
            });
        }
    }
    
    [self.tcpSocketManager setAutoDisconnectOnClosedReadStream:YES];
    
}

你可能感兴趣的:(局域网内端到端的聊天项目(五))