比特币源码解读十四

上篇我们已经进入了比特币的网络节点部分,并且了解了本机节点是如何获取自己的IP地址与外网地址的,我们现在接着往下看:使用域种子(dnsseed)查找节点。

使用dnsseed指令 查找节点

我们先了解下域种子(dnsseed):。IP地址是网络上标识站点的数字地址,为了方便记忆,采用域名来代替IP地址标识站点地址。域名解析就是域名到IP地址的转换过程。域名的解析工作由DNS服务器完成。

这些DNS服务器提供比特币节点的IP地址列表。 其中一些DNS种子提供了稳定的比特币侦听节点的静态IP地址列表。 一些DNS种子是BIND(Berkeley Internet Name Daemon)的自定义实现,它从搜索器或长时间运行的比特币节点收集的比特币节点地址列表中返回一个随机子集。 Bitcoin Core客户端包含五种不同DNS种子的名称。 不同DNS种子的所有权和多样性的多样性为初始引导过程提供了高水平的可靠性。 在Bitcoin Core客户端中,使用DNS种子的选项由选项switch -dnsseed控制(默认设置为1)

然后我们看下 ThreadDNSAddressSeed 这个函数是如何使用域查找IP地址的。

根据域名查找IP

下面,是通过对upnp端口的映射。

upnp端口映射

UPNP 的英文全称是Universal Plug and Play,即通用即插即用。是各种各样的智能设备、无线设备和个人电脑等实现遍布全球的对等网络连接(P2P)的结构。

比特币客户端是支持UPNP的,所以需要地址映射,我们现在就看下是如何映射的。要映射upnp设备是需要miniupnpc.lib这个库,用于映射端口的API是UPNP_AddPortMapping这个接口。我们现在就看下源码。

upnp端口映射

这部分我们了解了 UPNP的一些操作API,关于更多这方面的API,大家可以自行搜索。现在我们了解了如何发现其他节点和设备,现在我们就了解下和其他节点的消息通讯都做了哪些事情,这部分就是对各种消息的侦听。我们就先看下ThreadSocketHandler这个接口。我们和其他节点连通后,就需要进行消息交换,发送和接收数据就是通过这个接口来进行的,我们现在就看下这个函数的内部都做了些什么。这部分的源码非常多,我们分几个部分介绍:

1.在节点列表里查找已经失去连接和未用的节点并删除

删除无用节点

2.查找哪个socket连接有数据接收

这里的源码使用了文件描述符集fd_set(file descript set),既然其名字是一种集合,其实就是一long类型的数组,每一个数组元素都能与一打开的文件句柄(不管是socket句柄,还是其他文件或命名管道或设备句柄)建立联系,建立联系的工作由程序员完成,当调用select()时,由内核根据IO状态修改fd_set的内容,由此来通知执行了select()的进程哪一socket或文件发生了可读或可写事件。

这里最重要的是select()函数,采用select()的方式原因是 :使用Select就可以完成非阻塞。(所谓非阻塞方式non-block,就是进程或线程执行此函数时不必非要等待事件的发生,一旦执行肯定返回,以返回值的不同来反映函数的执行情况,如果事件发生则与阻塞方式相同,若事件没有发生则返回一个代码来告知事件未发生,而进程或线程继续执行,所以效率较高)方式工作的程序,它能够监视我们需要监视的文件描述符的变化情况——读写或是异常。

Select的函数格式(我所说的是Unix系统下的伯克利socket编程 )我们看下其原型和参数。

int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);

maxfdp:是一个整数值,是指集合中所有文件描述符的范围,即所有文件描述符的最大值加1,不能错!在Windows中这个参数的值无所谓,可以设置不正确

readfds:指向fd_set结构的指针,这个集合中应该包括文件描述符,我们是要监视这些文件描述符的读变化的,即我们关心是否可以从这些文件中读取数据了,如果这个集合中有一个文件可读,select就会返回一个大于0的值,表示有文件可读,如果没有可读的文件,则根据timeout参数再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值。可以传入NULL值,表示不关心任何文件的读变化

writefds:和readfds同理,只不过描述的是 是否可以从这些文件中写数据了。

errorfds:用来监听读写文件或socket的异常。

timeout:用来设置超时时间。它可以使select处于三种状态,第一,若将NULL以形参传入,即不传入时间结构,就是将select置于阻塞状态,一定等到监视文件描述符集合中某个文件描述符发生变化为止;第二,若将时间值设为0秒0毫秒,就变成一个纯粹的非阻塞函数,不管文件描述符是否有变化,都立刻返回继续执行,文件无变化返回0,有变化返回一个正值;第三,timeout的值大于0,这就是等待的超时时间,即select在timeout时间内阻塞,超时时间之内有事件到来就返回了,否则在超时后不管怎样一定返回,返回值同上述。

函数返回值:

负值:select错误 正值:某些文件可读写或出错 0:等待超时,没有可读写或错误的文件。

有了上面的认识后,我们再看下源码:

设置相应的sokcet侦听描述符

3.接收一个连接

因为我们每个节点既是其他节点的服务端,也是其他节点的客户端,所以首先把我们当服务器的时候,需要接收其他节点的连接,这就是我们要介绍的accept函数。

accept函数指定服务端去接受客户端的连接,接收后,返回了客户端套接字的标识,且获得了客户端套接字的“地方”(包括客户端IP和端口信息等)。

接收其他节点的连接

4.从其他节点接收发送的数据

接收数据

socket接收从其他节点发送的数据使用的是recv()函数。

(1)recv先等待s的发送缓冲中的数据被协议传送完毕,如果协议在传送s的发送缓冲中的数据时出现网络错误,那么recv函数返回SOCKET_ERROR;

(2)如果s的发送缓冲中没有数据或者数据被协议成功发送完毕后,recv先检查套接字s的接收缓冲区,如果s接收缓冲区中没有数据或者协议正在接收数据,那么recv就一直等待,直到协议把数据接收完毕。当协议把数据接收完毕,recv函数就把s的接收缓冲中的数据copy到buf中(注意协议接收到的数据可能大于buf的长度,所以在这种情况下要调用几次recv函数才能把s的接收缓冲中的数据copy完。recv函数仅仅是copy数据,真正的接收数据是协议来完成的);

recv函数返回其实际copy的字节数。如果recv在copy时出错,那么它返回SOCKET_ERROR;如果recv函数在等待协议接收数据时网络中断了,那么它返回0。

有了这个描述,应该就可以了解上面的代码了。有了接收就要有发送,下面就是向其他节点通过socket 发送数据的代码。

发送消息和连接状态检测

这里我们重要看下SocketSendData()函数,看下是如何发送数据的。在看源码前我们也介绍下socket的一个send()函数,此函数就是向Socket另一方发送数据的函数()。函数原型为:

int send( SOCKET s, const char FAR *buf, int len, int flags );

该函数的第一个参数指定发送端套接字描述符;

第二个参数指明一个存放应用程序要发送数据的缓冲区;

第三个参数指明实际要发送的数据的字节数;

第四个参数为标志位,一般情况下设置为MSG_NOSIGNAL(表示发送动作不愿被SIGPIPE信号中断),同时还有其他标志如:MSG_OOB(发送带外数据)MSG_DONTROUTE(告诉IP协议,目的主机在本地网络,没有必要查找路由表)MSG_DONTWAIT(设置为非阻塞操作)

发送数据

今天的内容应该是比较多了,我们了解了域种子,UPNP设备端口映射,fd_set(文件描述集),Socket的通讯。这也是获取其他节点的IP地址的目的。也是网络中进行通讯的常用方式。这篇就写到这里了。大家可以在网络中搜相关内容进行详细了解。




作者:区块链研习社比特币源码研读班,black

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容