欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

比特币早期版本P2P之IRC通信说明

程序员文章站 2022-03-10 12:16:06
...

比特币早期版本P2P之IRC通信说明

----红亚太学链:yjh、bjgpdn
    比特币的前几个版本使用IRC作为比特币P2P的seed,以此获取到比特币内节点的地址。本文讲述IRC的基本原理,及比特币如何使用IRC作为seed获取其它节点地址。

IRC基本原理

    Internet Relay Chat因特网中继聊天,一般称为互联网中继聊天,简称:IRC。它是由芬兰人Jarkko Oikarinen于1988年首创的一种网络聊天协议。
    IRC的原理十分简单,用户只需连接到IRC中继服务器,通过服务器中继连接到服务器上其它的用户进行通信。
    一个用户要与其它用户进行交谈,首先要有一个昵称,其次是要选择一个频道。
    频道的本质是广播组。当某个频道内的用户发送一条消息时,频道内的所有其它用户都会收到消息。
    IRC的服务器实际上就是起到中继的作用。用户将信息发送到服务器,服务器负责发送到广播组。这种中转模式为信息广播提供了方便。
    IRC的最大特点是实现了在线实时交谈,速度快、功能多的优点使它比电子邮件或新闻组等联络沟通方式更具吸引力。
    IRC上的信息交流采用请求与应答的模式. 请求是由服务器或客户端发出的,其目的是请求(另)一个服务器执行某个操作或提供某些信息; 应答是服务器对一个请求的回应信息. 请求通常被称为命令; 由于对每种应答都规定了一个三位数字做标识,应答也称为数字应答。
    以上内容摘自百度百科
    附一结构图:
比特币早期版本P2P之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通信说明
    下面是从比特币源码中摘取的P2P代码程序演示:
比特币早期版本P2P之IRC通信说明    首先向IRC服务器发送昵称,然后发送加入#bitcoin请求和频道用户列表请求。可以看到我们的用户名是u开头的由大小写字母和数字组成的base58编码。
比特币早期版本P2P之IRC通信说明
    之后会收到一连串IRC服务器发来的消息,就是服务器发来的一些消息。
比特币早期版本P2P之IRC通信说明
比特币早期版本P2P之IRC通信说明
    在这之后服务器响应请求,发来#bitcoin用户列表(GOT WHO),当识别到有’u’开头的昵称时 ,代表可能是比特币节点用户,则对该昵称进行反编码得到地址并尝试连接。由于现在比特币不再使用IRC来seed节点,所以现在比特币频道的用户的名字几乎都不是’u’开头的,也就无从获取地址了。另外还可以收到其它新用户的JOIN信息。

    感兴趣的同学可以自己开一个频道,然后两台电脑分别登录这个频道,这样两台电脑应该可以互相识别对面的昵称,并反编码获取地址。

    不过需要说明的是,即使得到外网地址,两个节点也无法连接。在现在的网络情况,电脑的IP几乎都是隐藏在多层NAT转换之下的局域网IP,即使获取到外网的IP,一来由于网络出口不同,外部IP动态变化,二来许多内网主机共用一个外网IP,仅仅使用外网IP地址无法定位到目标主机(以前好像是有默认静态NAT,外网的8333端口会绑定到内网用8333作为端口发送过消息的主机)。所以比特币后续的几个版本改为接收指定服务器发来的IP+Port信息,然后将该信息编码为昵称。

相关标签: 比特币