因此,我们不需要唯一的IP地址:唯一的Firebase键值(类似于域名)足以唯一地标识对等体,并且每个对等体在本地为每个需要转换的键分配“假”IP地址。 这完全消除了全局 IP 地址分配的需要,这是一项重要的任务。
这是我们需要实现的最小 API:
// Create and destroy a socket
int socket();
int close(int fd);
// Bind a socket to a port, and publish it on Firebase
int bind(int fd, AddrInfo* addr);
// Send a packet. This lazily create a WebRTC connection to the
// peer when necessary
int sendto(int fd, uint8_t* buf, int len, const AddrInfo* addr);
// Receive the packets destined to this socket
int recvfrom(int fd, uint8_t* buf, int len, AddrInfo* addr);
// Be notified when new packets arrived
int recvCallback(Callback cb);
// Obtain a local ip address for this peer key
uint32_t resolve(client::String* key);
// Get the peer key for this ip
String* reverseResolve(uint32_t addr);
// Get the local peer key
String* local_key();
// Initialize the library with the given Firebase database and
// WebRTc connection options
void init(client::FirebaseConfig* fb, client::RTCConfiguration* ice);
该 API 很简单,与 Posix Sockets API 类似,但有一些重要的区别: 记录回调、分配本地 IP 和惰性连接.
while(running) {
select(...); // wait for I/O events
while(true) {
int r = readfrom(...); // try to read
if (r < 0 && errno == EWOULDBLOCK) // no more data available
break;
...
}
...
}
如果事件循环对我们来说是隐藏的,那么我们需要将其变成这样:
auto cb = []() { // this will be called when new data is available
while(true) {
int r = readfrom(...); // try to read
if (r < 0 && errno == EWOULDBLOCK) // no more data available
break;
...
}
...
};
recvCallback(cb); // register the callback
本地IP分配
我们“网络”中的节点 ID 不是 IP 地址,而是 Firebase 键(它们是如下所示的字符串: -LmEC50PYZLCiCP-vqde ).
这很方便,因为我们不需要分配 IP 和检查其唯一性(以及在客户端断开连接后处理它们)的机制,但通常需要通过数值来识别对等点。
这正是这些函数的用途。 resolve и reverseResolve:应用程序以某种方式接收密钥的字符串值(通过用户输入或通过主服务器),并可以将其转换为 IP 地址以供内部使用。 为了简单起见,API 的其余部分也接收此值而不是字符串。