ICE
当我们想要实现在公网环境下的语音/视频通话功能时,就需要用到ICE交互式连接建立。ICE不是一种协议,整合了 STUN 和 TURN 两种协议(用于 NAT 穿透)的框架。
ICE的主要目标是解决NAT(网络地址转换)穿越问题,使得即使在复杂的网络环境下,如防火墙和NAT路由器后面,两个对等体也能够发现彼此并建立连接。
ICE的操作过程如下:
- 收集 Candidate
- 交换 Cadidate
- 按优先级尝试连接
Candidate
在WebRTC中,Candidate(候选) 是指用于在两个对等体(peers)之间建立连接的所有可能的网络地址和传输方式。这些候选包括了本地IP地址、端口号以及可能需要的中继服务器信息。候选的目的是提供一个或多个路径,以便在因网络限制(如NAT、防火墙)而无法直接连接的请款下,仍能够建立通信。
STUN
STUN是一种网络协议,主要目的是解决因NAT(网络地址转换)导致的端到端直接通信问题。STUN提供了一种方法,允许位于NAT后面的设备发现他们在公共互连网上的IP地址和端口号,以及NAT设备的类型。这样,这些设备可以被其他互连网上的设备发现和链接。
简单点说就是获取主机公网IP的。
STUN的工作流程如下:
- 客户端请求:位于NAT后面的客户端向STUN服务器发送一个请求。
- 服务器响应:STUN服务器收到请求后,会将请求的源IP地址和端口号(即客户端在公共互连网上的地址)作为响应的一部分发送回客户端。
- 客户端发现:客户端通过STUN服务器的响应知道了自己在公网上的IP和端口
- 交换信息:客户端之前可以交换这些信息,尝试直接连接。
交换信息是通过信令通道实现的,STUN主要任务是前两步
STUN服务器通常是一个简单的服务,它监听UDP端口(通常是3478),并响应发往该端口的STUN请求。
客户端通过STUN服务器建立连接成功时,用户之间是直接连接的。
STUN协议的局限性在于,它只能帮助设备发现自己的公网地址,但并不能保证两个设备能够直接通信。如果NAT设备不允许未经初始化的外部连接,即使知道了对方的公网地址,直接连接仍可能失败。在这种情况下,可能需要使用TURN协议,它通过中继流量来实现通信。
TURN
TURN协议是一个用于解决NAT穿透问题的协议,它是STUN协议的一个扩展。TURN协议通过在服务器上设置中继服务器,允许NAT后面的客户端之间进行通信。当两个客户端直接建立连接时,例如由于严格的NAT策略,TURN服务器会介入,接收来自一个客户端的数据并转发给另一个客户端。
在WebRTC中,TURN服务器提供了一个中继点,用于在对等体(peers)之间转发数据包。如果STUN协议无法实现直接连接,TURN协议就会作为备选方案,确保通信的建立。
客户端通过TURN建立连接成功时:
Coturn服务器搭建
下载地址:coturn/coturn: coturn TURN server project (github.com)
官网提供了包管理器和 docker 两种方式。
apt
apt install coturn
turnserver --log-file stdout
docker
docker run -d -p 3478:3478 -p 3478:3478/udp -p 5349:5349 -p 5349:5349/udp -p 49152-65535:49152-65535/udp coturn/coturn
由于我使用的阿里云ecs配置为2核2G,使用docker启动容器会直接卡死,下面采用包管理器进行安装。
下载 coturn
centos 可以使用 yum 下载 coturn
sudo yum install coturn
使用 openssl 生成 cert 和 pkey 配置的自签名证书
openssl req -x509 -newkey rsa:2048 -keyout /etc/turn_server_pkey.pem -out /etc/turn_server_cert.pem -days 99999 -nodes
生成的证书默认位于/etc/turn_server_cert.pem、/etc/turn_server_pkey.pem
修改配置
修改 coturn 配置
vim /etc/coturn/turnserver.conf
可以通过ifconfig
命令查看内网IP,也可以在实例首页查看
修改为自己的内网、公网IP,用户名和密码可以自定义。
# 网卡名
relay-device=eth0
#内网IP
listening-ip=172.24.65.118
listening-port=3478
#内网IP
relay-ip=172.24.65.118
tls-listening-port=5349
# 外网IP
external-ip=47.121.25.229
relay-threads=500
#打开密码验证
lt-cred-mech
cert=/etc/turn_server_cert.pem
pkey=/etc/turn_server_pkey.pem
#设置用户名和密码,创建IceServer时使用
user=hhh:123456
# 外网IP绑定的域名
realm=47.121.25.229
# 服务器名称,用于OAuth认证,默认和realm相同,部分浏览器本段不设可能会引发cors错误。
server-name=47.121.25.229
# 认证密码,和前面设置的密码保持一致
cli-password=123456
udp 3478 用于STUN服务,tcp 3478 用于TURN服务,默认 udp 49152-65535 用于媒体中继,需要为这些端口配置安全组。
启动 coturn
turnserver -o -a -f
测试:Trickle ICE (webrtc.github.io)
If you test a STUN server, it works if you can gather a candidate with type “srflx”. If you test a TURN server, it works if you can gather a candidate with type “relay”.
如果您测试一个STUN服务器,如果您可以收集类型为“srflx”的候选服务器,它就可以工作。如果您测试一个TURN服务器,如果您可以收集类型为“relay”的候选服务器,它就可以工作
填写自己的服务器信息,并点击“Add Server”
点击下方的“Gather candidates”。若收集到了srflx
和 relay
类型的候选服务器,表示STUN和TURN可以工作。
要在JavaScript中使用TURN服务器,你需要在你的WebRTC代码中配置PTCPeerConnection对象,以包含TURN服务器的信息,例如:
const peerConnection = new RTCPeerConnection({
iceServers: [
{
urls: 'turn:ip:3478', // 你的TURN服务器地址和端口
username: '', // 如果需要,填入你的TURN用户名
credential: '', // 如果需要,填入你的TURN密码
}
]
});