比特幣早期版本P2P之IRC通信說明

比特幣早期版本P2P之IRC通信說明

----紅亞太學鏈:yjh、bjgpdn
    比特幣的前幾個版本使用IRC作爲比特幣P2P的seed,以此獲取到比特幣內節點的地址。本文講述IRC的基本原理,及比特幣如何使用IRC作爲seed獲取其它節點地址。

IRC基本原理

    Internet Relay Chat因特網中繼聊天,一般稱爲互聯網中繼聊天,簡稱:IRC。它是由芬蘭人Jarkko Oikarinen於1988年首創的一種網絡聊天協議。
    IRC的原理十分簡單,用戶只需連接到IRC中繼服務器,通過服務器中繼連接到服務器上其它的用戶進行通信。
    一個用戶要與其它用戶進行交談,首先要有一個暱稱,其次是要選擇一個頻道。
    頻道的本質是廣播組。當某個頻道內的用戶發送一條消息時,頻道內的所有其它用戶都會收到消息。
    IRC的服務器實際上就是起到中繼的作用。用戶將信息發送到服務器,服務器負責發送到廣播組。這種中轉模式爲信息廣播提供了方便。
    IRC的最大特點是實現了在線實時交談,速度快、功能多的優點使它比電子郵件或新聞組等聯絡溝通方式更具吸引力。
    IRC上的信息交流採用請求與應答的模式. 請求是由服務器或客戶端發出的,其目的是請求(另)一個服務器執行某個操作或提供某些信息; 應答是服務器對一個請求的迴應信息. 請求通常被稱爲命令; 由於對每種應答都規定了一個三位數字做標識,應答也稱爲數字應答。
    以上內容摘自百度百科
    附一結構圖:
在這裏插入圖片描述IRCSeed的原理
    IRC的信息交流採用請求與應答模式,通過sockect編程與IRC服務器進行通訊可以達到使用IRC的目的。
    比特幣早期版本就是使用IRC作爲P2P的seed,想要連接到比特幣節點的用戶可以通過連接IRC服務器,並進入指定的#bitcoin頻道從而達到你獲取到頻道內其它節點地址的效果。
    下面是詳細原理流程:
    下面展示一些 內聯代碼片

struct hostent* phostent = gethostbyname("chat.freenode.net");
CAddress addrConnect(*(u_long*)phostent->h_addr_list[0], htons(8001));
SOCKET hSocket;
if (!ConnectSocket(addrConnect, hSocket))
{
    printf("IRC connect failed\n");
    return;
}

    首先tcp連接到IRC的服務器。IRC服務器有很多,之前國內也有,現在很少了,我們使用的是http://chat.freenode.net,可以用於連接的端口號也有好幾個,可以去這個網站上,有介紹文檔,我們使用的是8001端口,連不上就換一個連。

stringstrMyName = EncodeAddress(addrLocalHost);//編碼外網網址

    之後本地節點獲得自己的外網地址(內網地址不行),並將地址通過base58格式進行編碼。編碼的內容前面加上字符‘u’作爲自己的暱稱。

    值得一提的是,早期版本的比特幣通過特定IP服務網站,讓網站返回自己的外網IP,但是僅僅得到IP對現在的網絡情況已經不適用了,後面會繼續做進一步解釋,從比特幣中間幾個版本開始,訪問的服務網站將返回IP+Port而不僅僅是IP地址。

Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
Send(hSocket, strprintf("USER %s 8 * : %s\r", strMyName.c_str(), strMyName.c_str()).c_str());

    向IRC服務器發送由地址編碼得到的暱稱信息。

Send(hSocket, "JOIN #bitcoin\r");
Send(hSocket, "WHO #bitcoin\r");

    向IRC服務器發送加入比特幣#bitcoin頻道的JOIN請求,和請求頻道內用戶列表的WHO請求.
    後續就是進入比特幣頻道,並開始接收服務器發來的#bitcoin用戶列表消息以及其它用戶的JOIN消息或者普通消息。

if (pszName[0] == 'u')
{
    CAddress addr;
    if (DecodeAddress(pszName, addr))
    {    CAddrDB addrdb;
        if (AddAddress(addrdb, addr))
         ......
    }
}

    前面提到,比特幣程序將地址用base58編碼並在前面加上字符’u’作爲暱稱。當收到’u’開頭的暱稱時,則代表可能是地址,於是對該暱稱進行反編碼從而獲得對方地址。然後將地址加入mapAddresses地址表。後續會進行連接嘗試。

    以上就是比特幣程序將IRC作爲seed的基本過程。

    附一張時序圖:
在這裏插入圖片描述
    下面是從比特幣源碼中摘取的P2P代碼程序演示:
在這裏插入圖片描述    首先向IRC服務器發送暱稱,然後發送加入#bitcoin請求和頻道用戶列表請求。可以看到我們的用戶名是u開頭的由大小寫字母和數字組成的base58編碼。
在這裏插入圖片描述
    之後會收到一連串IRC服務器發來的消息,就是服務器發來的一些消息。
在這裏插入圖片描述
在這裏插入圖片描述
    在這之後服務器響應請求,發來#bitcoin用戶列表(GOT WHO),當識別到有’u’開頭的暱稱時 ,代表可能是比特幣節點用戶,則對該暱稱進行反編碼得到地址並嘗試連接。由於現在比特幣不再使用IRC來seed節點,所以現在比特幣頻道的用戶的名字幾乎都不是’u’開頭的,也就無從獲取地址了。另外還可以收到其它新用戶的JOIN信息。

    感興趣的同學可以自己開一個頻道,然後兩臺電腦分別登錄這個頻道,這樣兩臺電腦應該可以互相識別對面的暱稱,並反編碼獲取地址。

    不過需要說明的是,即使得到外網地址,兩個節點也無法連接。在現在的網絡情況,電腦的IP幾乎都是隱藏在多層NAT轉換之下的局域網IP,即使獲取到外網的IP,一來由於網絡出口不同,外部IP動態變化,二來許多內網主機共用一個外網IP,僅僅使用外網IP地址無法定位到目標主機(以前好像是有默認靜態NAT,外網的8333端口會綁定到內網用8333作爲端口發送過消息的主機)。所以比特幣後續的幾個版本改爲接收指定服務器發來的IP+Port信息,然後將該信息編碼爲暱稱。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章