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

效果图:
iPod.gif
iPhone.gif
  • 上一篇已实现单张图片的相互传输
  • 接下来实现多张图片的传输
1.图片的来源及传输方式不变
2.当接收方收到的是媒体文件时 需要把媒体文件流写入磁盘后 在发送一个特定指令到发送方 这样就不会造成错乱 (ps:传输失败还需在考虑)
3.发送方在接收到特定指令后会去循环缓存集合,发送第一个缓存消息体
4.最终的传输方式还是一条一条的传输
一.图片选择后发送的方法不变
- (void)sendImageOrVideo{
    WS(weakSelf);
    [[PickerImageVideoTool sharePickerImageVideoTool] showImagePickerWithMaxCount:9 completion:^(NSArray<UIImage *> *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];
    
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,590评论 18 139
  • __block和__weak修饰符的区别其实是挺明显的:1.__block不管是ARC还是MRC模式下都可以使用,...
    LZM轮回阅读 3,278评论 0 6
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,016评论 4 62
  • 上下文选择符 p em {} 只要em的祖先元素有p就满足。p>em{}必须是em的父元素是p才满足。 p + i...
    jiango86阅读 162评论 0 0
  • 脸型与发型的搭配有很多技巧,一般我们人的脸型分为几种:圆脸、方脸、梨型脸、长脸型、钻石型脸、心型脸、不均匀脸七种,...
    陈家大欢欢阅读 825评论 0 0