RTMFP---基于CumulusServer的P2P功能实现
后烨煜
2023-12-01
今天周末抽空分享下用CumulusServer实现P2P的原理和过程,同时共享服务器和客户端的完整可编译可执行代码
P2P的实现原理:
最核心的部分有两个:
Client1与Client2如何完成P2P的连接、udp穿越
Client1与Client2P2P的连接:
Client1与Client2不知对方地址,所以要去服务器要对方地址
CumulusServer服务器对每个客户端都有分配一个唯一的peerid,同时,需要修改代码为每个客户端增加一个uid
Uid是web数据库分配的,是web上对于客户端的唯一标示,peerid是服务器分配的,是服务器上对于客户端的唯一标示
这样用uid + peerid即可将 服务器+客户端+web串联起来:
client1的web界面上点击client2发起点对点的私聊,client1可以根据client2的uid向服务器查询client2的peerid
Client1有了对方的peerid接下来就好办了:
课通过
rns = new NetStream(conn,farId); //farId是client2的peerid,即连接的目的端的peerid
rns.play(...)发出P2P的请求,CumulusServer服务器收到客户端的P2P请求后,
根据farId可以找到client2的地址等信息,完成UDP打洞后将P2P的请求转发给client2
这样client2和client1即可完成P2P连接
udp穿越:
原理上可以参考帖子http://www.haogongju.net/art/1702940
从测试看 CumulusServer的 RTMFPServer::p2pHandshake函数能够完成udp穿越功能
P2P的实现过程:
第一步:Client1连接服务器
conn.connect(“rtmfp://121.10.139.211”);
服务器为Client1分配peerid
第二步:Client2连接服务器
conn.connect(“rtmfp://121.10.139.211”);
服务器为Client2分配peerid
第三步:Client1找服务器要 client2的peerid:
conn.call("GetPidFromServer",null,"53c91b70-717b-4a23-94ef-room2client2");
第四步:client2找服务器要 client1的peerid:
conn.call("GetPidFromServer",null,"53c91b70-717b-4a23-94ef-room2zhubo1");
第五步:client1发出publish
pns = new NetStream(conn,NetStream.DIRECT_CONNECTIONS);
NetStream.DIRECT_CONNECTIONS----所有与client1直连的端都会收到其publish的数据
第六步:client2发出P2P连接请求
rns = new NetStream(conn,farId);
... ...
rns.play("somes99"+txtLogin.text);
注:farId为client1的peerid,play请求会先发送到服务器CumulusServer
CumulusServer会调用 RTMFPServer::p2pHandshake函数完成udp打洞同时将P2P的请求发送到client2
从而完成Client1和client2的P2P连接
至此,P2P整个过程完毕,clinet2可以得到client1的视频和音频流了
上面是client1做publish,client2做play,简单修改可以做到client1和client2互取对方数据,或者client1发送音视频数据给多个客户端都可以
P2P的实现代码:
详见我个人的资源空间
遗留问题:
P2P最大的好处是减少服务器的带宽消耗
但是当前我碰到的难题是:
1、每个客户端的上传速度是有限制的,一个客户端到底该publish码流给几个客户端合适?
2、client1共享码流给client2,client2又共享给client3....这样层层共享,越往后面中转次数越多岂不是延时越大?
六间房、齐齐视频等直播平台都没有用P2P的模式(客户端只有下载没有上传),不知道这些大型直播平台没有用p2P的原因