Peer代表P2P的一个参与方。它内部包含一个P2PServer,用来接收、发送udp消息。
源代码
传文件api设计的时候考虑了易用性、速度、性能消耗等多重因素,它能够以几十MB的内存占用来传输以GB为单位的文件。
在我的Surface Pro 6上,两个Peer传输2.33GB的文件只需要10秒左右,平均速度能到230MB每秒。而这可能仍然不是它的极限。我的cpu运算速度可能限制了它。
[!NOTE] 大部分实际情况下传文件的速度会远小于它的极限速度。因为瓶颈效应,传文件速度会受到网路上硬件设备和硬盘读写速度的限制。在华科网安基地的校园网中,两个机器的最大传输速度只有2-3MB每秒。而在我家里则能快10倍。即使是本机两个Peer互传,机械硬盘的传输速度也有可能比SSD慢近10倍
大文件在发送前会被分片,然后使用可靠udp传输。而文件片被接收的时候顺序可能和发送的时候不一样。我们使用了一种特殊的方法,避免了重新排序,从而大大增加了传输速率。
[!TIP] 众所周知,一般好的排序算法时间复杂度都是,空间复杂度也可能很大。所以对于大文件这种分片非常多的场景,应当避免使用这些普通排序算法。
文件分片在接收的时候,有个很好的性质:整体有序。也就是说它的分片到达的时候虽然时有乱序,但是总体而言编号是一直增大的。所以我们可以使用字典来进行一种特殊的排序。
算法:
初始化一个long类型的值,名为head。它初值为-1,表示一个指针,指向上一个已经写入文件流的数据片的编号。
初始化一个字典,字典的键类型为数据片编号的类型,字典的值类型为数据片的类型
开始接收文件数据
等待接收数据片
接收到一个数据片
若文件片编号等于head的值加1:
直接将该数据片写入文件流
head值加1
在字典中查找编号为head+1的数据
若找到:
从字典里删除该键值对
跳转5.1
若没找到则跳转4
[!NOTE] 上述过程省略了一部分步骤,比如判断文件传输结束。
[!NOTE] 上述过程必须串行发生,而设计的时候处理请求可能是并发的,所以需要加同步机制。考虑到锁是一种低效的同步方式,为了性能我们使用了semaphore。
以上算法在实际使用中时间复杂度复杂度接近,空间复杂度为常数
我们的实时流api能够用来实现实时语音通话或视频的功能。它接收一个MsgQueue,发送的信息使用普通udp传输。
本文章使用limfx的vscode插件快速发布