# WebRTC

// todo


## NAT穿透
`NAT`在解决IPv4紧张和提高安全性的同时，也会很大程度上破坏`P2P`通信，处于`NAT`设备下的客户端`A`，其他客户端（非同一局域网或者同一局域网下互不知晓）要主动访问该客户端，会被`A`的`NAT`设备拒绝，必须要`A`留下“洞”（参见下面的`NAT类型`)后，才有可能访问到。

### NAT类型

* 锥型NAT
    * 完全锥型：只要内网客户端`A`，由内到外建立一个映射（`innerIP:innerPort -> NatIP:NatPort -> B:P1`）之后，其他IP的主机C或端口B:P2都可以使用这个洞(`NatIP:NatPort`)给`A`发送数据
    * 受限锥型NAT：`A`: `innerIP:innerPort -> NatIP:NatPort -> B:P1`后，`B`上任意端口程序都可以通过`NatIP:NatPort`访问到`A`，即限制IP，不限制端口
    * 端口受限型NAT: `A`: `innerIP:innerPort -> NatIP:NatPort -> B:P1`后，`B`上只有被映射为`B:P1`的程序才可以通过`NatIP:NatPort`访问到`A`
* 对称型NAT
    * 内网客户端`A`每访问不同`IP:Port`时，都会建立一个不同的`innerIP:innerPort -> NatIP:NatPort`映射，目标客户端此时必须要通过对应的洞访问`A`

### 反向连接

适用于通信双方只有一方处于`NAT`设备后面的情况。

假设有处于`NAT`下的`client A`、公网服务器、处于公网的`client B`，`client A`可以自由访问`client B`，但是`B`请求`A`时，会被`NAT`设备拒绝。要想与`B`通信， `A`不是直接向`B`发起连接，而是通过服务器给`B`转发一个连接请求，反过来请求`B`连接到`A`（即进行反向链接），`B`在收到从服务器转发过来的请求以后，会主动向`A`发起一个TCP的连接请求，这样在NAT设备上就会建立起关于这个连接的相关表项，使`A`和`B`之间能够正常通信。

### UDP打洞

UDP打洞技术是通过中间服务器的协助在各自的`NAT网关`上建立相关的表项，使P2P连接的双方发送的报文能够直接穿透对方的NAT网关，从而实现P2P客户端互连。如果两台位于NAT设备后面的P2P客户端希望在自己的NAT网关上打个洞，那么他们需要一个协助者——集中服务器，并且还需要一种用于打洞的`Session`建立机制。

**中继服务器**

中继服务器用于协助打洞，希望进行P2P通信的双方都会向中继服务器进行登陆。在客户端向服务器发送的登陆消息中，包含有客户端的内网地址二元组信息；同时会把自己观察到的客户端的外网地址二元组信息记录下来。通过判断这两个二原组信息可以判断客户端是否处于`NAT`下。

**实例**

假设有两个客户端(都处于NAT下)：
```
客户端A——>本地IP:10.0.0.1，本地端口:4321，外网IP:155.99.25.11，外网端口:62000

客户端B——>本地IP:10.1.1.3，本地端口:4321，外网IP:138.76.29.7，外网端口:31000
```

在`A`向服务器发送的登陆消息中，包含有A的内网地址二元组信息，即`10.0.0.1:4321`；服务器会记录下`A`的内网地址二元组信息，同时会把自己观察到的`A`的外网地址二元组信息记录下来。同理，服务器也会记录下`B`的内网地址二元组信息和由服务器观察到的客户端`B`的外网地址二元组信息。无论`A`与`B`二者中的任何一方向服务器发送P2P连接请求，服务器都会将其记录下来的上述的外网和内网地址二元组发送给`A`或`B`。

之后`A`和`B`都会开始互相`打洞`，`A`发送请求到`B`的IP，`B`发送请求到`A`的IP，假如`A`发送的请求在`B`向`A`发出请求之前到达`B`，那么`B`的`NAT`设备会拒绝该请求，然后`A`会继续发送打洞请求，直到某次打洞请求时，`B`已经向`A`发送请求（即在`B`的NAT设备上建立了对应表项），打洞成功。`B`也类似。

`A`与`B`向对方的外网地址发送数据，等效为向对方的客户端直接发送UDP数据包了。一旦应用程序确认已经可以通过往对方的外网地址发送数据包的方式让数据包到达NAT后面的目的应用程序，程序会自动停止继续发送用于“打洞”的数据包，转而开始真正的P2P数据传输。
