作为WebRTC的三大模块之一,DataChannel支持短消息(short message)二进制和文本数据的传输,因此,对于通常以传输音视频为主的WebRTC来说,当需要传输音视频以外的数据的时候就有很大用处了。
这样听起来,DataChannel
看起来和Websocket
实现的功能很相似。的确,DataChannel模型最初是基于webSocket建立的,具有简单可设置的send方法和onMessage方法。但是它们之间的区别是很明显的:
1、RTCDataChannel通信是在peer与peer之间直接连接,所以RTCDataChannel比WebSocket更快,因为WebSocket需要服务器中转;但是相应的,WebRTC依靠ICE Servers来穿透NAT,有的场景下可能会多一层TURN服务器的转发。
2、WebSocket协议是基于TCP传输的,它能够保证数据的安全有序地到达;而RTCDataChannel是基于SCTP传输协议(SCTP是一种TCP、UDP同级的传输协议), 默认情况下是可靠有序传输。但是它也可以配置是否进行可靠的传输,这就意味着有可能会通过丢失数据来达到性能的要求,这使得RTCDataChannel更为灵活。这里说一下,为什么会有配置不可靠传输的需求呢?因为实时通信对时间是非常敏感的,以音视频为例,它可以容忍间接性的数据包丢失,可以通过算法来填补这个丢失的数据,因此WebRTC对及时性和低延时的要求要比数据传输的可靠性要求更高。
3、WebSocket构造需要一个url,与服务器建立连接,创建一个唯一的SocketSessionId;DataChannel 的连接依赖于一个RTCPeerConnection对象,当RTCPeerConnection建立起来后,可以包含一个或多个RTCDataChannel。
还有其他的一些区别,例如大文件传输时的拥塞控制、加密等,不在列举。
在IOS WebRTC中,要使用RTCDataChannel非常简单
#import <WebRTC/RTCDataChannel.h>
#import <WebRTC/RTCDataChannelConfiguration.h>
- (void)createDataChannelWithPeerConnection:(RTCPeerConnection*)peerConnection connectionId:(NSString*)connectionId{
//给p2p连接创建dataChannel
RTCDataChannelConfiguration *dataChannelConfiguration = [[RTCDataChannelConfiguration alloc] init];
dataChannelConfiguration.isNegotiated = NO;
RTCDataChannel* localDataChannel = [peerConnection dataChannelForLabel:@"localDataChannel" configuration:dataChannelConfiguration];
localDataChannel.delegate = self;
[self.localDataChannelDictionary setObject:localDataChannel forKey:connectionId];//本地记录一下
}
有一点很重要,就是DataChannel的创建是在生成本地offer之前,这样才能在生成offer后,使offer中包含DataChannel的信息。
关于DataChannel的配置参数,你可以查看<WebRTC/RTCDataChannelConfiguration.h>
中的各种参数及说明。
当创建好RTCDataChannel后,下面的回调会被执行:
/** New data channel has been opened. */
- (void)peerConnection:(RTCPeerConnection*)peerConnection didOpenDataChannel:(RTCDataChannel*)dataChannel{
NSLog(@"%s",__func__);
dataChannel.delegate = self;
}
不要忽略设置delegate = self哦,否则你是无法收发消息的。
发送消息:
-(void)sendMessage:(NSString *)message{
NSDictionary* messageDic = @{@"type":@"text",@"value":message};
NSData* messageData = [NSJSONSerialization dataWithJSONObject:messageDic options:NSJSONWritingPrettyPrinted error:nil];
RTCDataBuffer *buffer = [[RTCDataBuffer alloc] initWithData:messageData isBinary:NO];
[self.localDataChannelDictionary enumerateKeysAndObjectsUsingBlock:^(NSString* connectionId, RTCDataChannel* dataChannel, BOOL * _Nonnull stop) {
bool success = [dataChannel sendData:buffer];
if (success){
NSLog(@"sendmessageSuccess = %@",message);
}else{
NSLog(@"SendMessageFailed");
}
}];
}
这里需要说一下,如果使用RTCDataChannel发送图片,需要将type设置为image,并且进行base64编码。
当收到消息时,下面的回调会被执行:
/** The data channel successfully received a data buffer. */
- (void)dataChannel:(RTCDataChannel *)dataChannel didReceiveMessageWithBuffer:(RTCDataBuffer *)buffer{