效果图:
-
上一篇已实现单张图片的相互传输
- 接下来实现多张图片的传输
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];
}