比特币早期版本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信息,然后将该信息编码为昵称。
推荐阅读