因此,我們不需要唯一的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 的其餘部分也接收此值而不是字串。