# 客户端中继

目前存在这样一个问题: 假设存在三个客户端 A B C, A 能分别与 B 和 C 建立对等连接,但是 B 与 C 之间无法建立对等连接.此时连接只能退化为通过服务端转发,实际上让 A 作为中继转发 B 与 C 之间的流量是更优的解决方案.

现实中,中继 A 可能是多台设备,链路也并非只有 A 这一条.问题就可以扩展成: 如何在网络中的若干中继链路中需找代价最小的一条建立连接.

解决这个问题的方法是[路由算法](https://www.google.com/search?q=路由算法),本项目在此基础上实现.

## 如何确定两个节点间通信的代价

目前以时延作为唯一标准.如果两个节点无法建立对等连接,认为代价无限大.当某个节点拥堵时,时延会变高,当代价增大时,节点可以自动选择其他代价低的线路.

对等连接中新增 DELAY 报文,报文中携带发送方和接收方的虚拟地址,以及发送方系统启动到此刻的 64 位毫秒级时间戳.接收方不处理报文,仅将报文回传给发送方.发送方收到自己发送的报文后,根据报文中的时间戳计算时延.

## 如何更新路由表

路由表中记录通过 X 到到 Y 的代价 Z. 路由表初始状态为空.

当与某客户端成功建立对等连接后,通过 DELAY 报文获取时延并记录在表格中,此时 X 等于 Y, 并且 Z 为时延毫秒数.当有新客户端建立对等连接后,重复上述操作,并将这条记录广播给已经成功建立对等连接的设备,广播时 X 调整为本机.

当检测到与某个设备的对等连接断开后,从路由表里删除下一跳为该地址的所有记录,每条记录都发送一次广播,广播内容为与建立连接时相似,只是 Z 为一个特殊值,表示失联.

除了建立和断开连接,客户端还应该周期性的获取时延,更新并广播.

其他设备收到记录后,对比使用这条线路的延迟与当前已经记录的延迟: 如果延迟增高(或失联),且目的地址和下一跳地址与本机记录的相同,那么更新(或删除)本机记录并广播;如果延迟更低则更新记录并广播.

## 如何转发报文

当发送报文时,根据目的地址查找路由表,查找失败则使用服务端转发.查找成功后,将报文用下一跳可以解密的方式加密发送.下一跳收到报文后检查目的地址,如果为本机则直接处理,否则继续寻找下一跳.

## 其他说明

有些设备可能带宽费用很高,不能或者不适合作为中继设备,所以添加"路由代价"参数描述这一情况,"路由代价"将加上两设备间实际往返时延作为路由时延广播.
`route = 0` 时表示不启用本功能.最大取值为 1000, 对应真实往返时延 1 秒.如果想尽可能用本设备作为中继,应该配置 `route = 1`.

由于本功能只能在已经建立对等连接的设备中使用,因此添加主动发现功能,对于愿意主动作为中继的设备,可以启用这一功能让尽可能多的客户端发现自己.
`discovery = 0` 时不启用本功能. `discovery = 60` 表示每 60 秒发送一次广播报文.
