1、创建ns_g_socketmgr:

首先,套接字管理器是全局唯一的,与有多少个网络接口无关,全局变量定义在/bin/named/include/named/globals.h:

EXTERN isc_socketmgr_t *    ns_g_socketmgr        INIT(NULL);

#0  isc__socketmgr_create2 (mctx=0x8742d0, managerp=0x8701f8, maxsocks=0) at socket.c:4143
#1  0x000000000041919e in create_managers () at ./main.c:604
#2  0x0000000000419727 in setup () at ./main.c:850
#3  0x0000000000419a2b in main (argc=4, argv=0x7fffffffe5c8) at ./main.c:1058

使用多线程时,isc__socketmgr_create2会创建管道、select\epoll线程,工作线程通过管道控制select\epoll线程的工作。

2、扫描网络接口:

bind9启动时会扫描一下网络接口,运行期间会定时扫描,扫描间隔可以设置相应定时器,这样网络环境发生变化,bind9可以及时感知。bind9会为每一个网络接口创建两个监听套接字,为lo网络接口创建控制套接字。所以只有一个物理网卡的机器,在启动时会创建3个套接字。

udp监听套接字:

#  isc__socket_create (manager0=0x7ffff7fa9010, pf=, type=isc_sockettype_udp, socketp=0x7fffec7870c8) at socket.c:
# 0x00000000004861cc in open_socket (mgr=0x7ffff7fa9010, local=0x7ffff7fbe290, options=, sockp=0x7fffec7872f8)
at dispatch.c:
# 0x0000000000489b27 in get_udpsocket (mgr=0x7ffff7fae270, sockmgr=0x7ffff7fa9010, taskmgr=0x7ffff7fa5010,
localaddr=0x7ffff7fbe290, maxrequests=<value optimized out>, attributes=, dispp=0x7fffec787418) at dispatch.c:
# dispatch_createudp (mgr=0x7ffff7fae270, sockmgr=0x7ffff7fa9010, taskmgr=0x7ffff7fa5010, localaddr=0x7ffff7fbe290,
maxrequests=<value optimized out>, attributes=, dispp=0x7fffec787418) at dispatch.c:
# 0x000000000048a042 in dns_dispatch_getudp (mgr=0x7ffff7fae270, sockmgr=0x7ffff7fa9010, taskmgr=0x7ffff7fa5010,
localaddr=0x7ffff7fbe290, buffersize=<value optimized out>, maxbuffers=<value optimized out>, maxrequests=,
buckets=, increment=, attributes=, mask=, dispp=0x7ffff7fbe340) at dispatch.c:
# 0x000000000041520b in ns_interface_listenudp (ifp=0x7ffff7fbe250) at interfacemgr.c:
# 0x00000000004155e5 in ns_interface_setup (mgr=0x7ffff7fb6f70, addr=0x7fffec787700, name=0x7fffec787570 "eth0",
ifpret=0x7fffec787878, accept_tcp=isc_boolean_true) at interfacemgr.c:
# 0x0000000000416a16 in do_scan (mgr=0x7ffff7fb6f70, ext_listen=0x0, verbose=isc_boolean_true) at interfacemgr.c:
# 0x0000000000416bf2 in ns_interfacemgr_scan0 (mgr=0x7ffff7fb6f70, ext_listen=0x0, verbose=isc_boolean_true)
at interfacemgr.c:
# 0x0000000000416c92 in ns_interfacemgr_scan (mgr=0x7ffff7fb6f70, verbose=isc_boolean_true) at interfacemgr.c:
# 0x0000000000435107 in scan_interfaces (server=0x7ffff7fae010, verbose=isc_boolean_true) at server.c:
# 0x0000000000437d60 in load_configuration (filename=0x7fffffffe850 "/var/named/named.conf", server=0x7ffff7fae010,
first_time=isc_boolean_true) at server.c:
# 0x0000000000439fdf in run_server (task=0x7ffff7fba010, event=0x0) at server.c:
# 0x00000000005b3b15 in dispatch (manager=0x7ffff7fa5010) at task.c:
# 0x00000000005b3da1 in run (uap=0x7ffff7fa5010) at task.c:
# 0x0000003817a07a51 in start_thread () from /lib64/libpthread.so.
# 0x00000038176e896d in clone () from /lib64/libc.so.

tcp套接字:

#  isc__socket_create (manager0=0x7ffff7fa9010, pf=, type=isc_sockettype_tcp, socketp=0x7ffff7fbe348) at socket.c:
# 0x0000000000415344 in ns_interface_accepttcp (ifp=0x7ffff7fbe250) at interfacemgr.c:
# 0x0000000000415600 in ns_interface_setup (mgr=0x7ffff7fb6f70, addr=0x7fffec787700, name=0x7fffec787570 "eth0",
ifpret=0x7fffec787878, accept_tcp=isc_boolean_true) at interfacemgr.c:
# 0x0000000000416a16 in do_scan (mgr=0x7ffff7fb6f70, ext_listen=0x0, verbose=isc_boolean_true) at interfacemgr.c:
# 0x0000000000416bf2 in ns_interfacemgr_scan0 (mgr=0x7ffff7fb6f70, ext_listen=0x0, verbose=isc_boolean_true)
at interfacemgr.c:
# 0x0000000000416c92 in ns_interfacemgr_scan (mgr=0x7ffff7fb6f70, verbose=isc_boolean_true) at interfacemgr.c:
# 0x0000000000435107 in scan_interfaces (server=0x7ffff7fae010, verbose=isc_boolean_true) at server.c:
# 0x0000000000437d60 in load_configuration (filename=0x7fffffffe850 "/var/named/named.conf", server=0x7ffff7fae010,
first_time=isc_boolean_true) at server.c:
# 0x0000000000439fdf in run_server (task=0x7ffff7fba010, event=0x0) at server.c:
# 0x00000000005b3b15 in dispatch (manager=0x7ffff7fa5010) at task.c:
# 0x00000000005b3da1 in run (uap=0x7ffff7fa5010) at task.c:
# 0x0000003817a07a51 in start_thread () from /lib64/libpthread.so.
# 0x00000038176e896d in clone () from /lib64/libc.so.

rndc控制套接字:

#  isc__socket_create (manager0=0x7ffff7fa9010, pf=, type=isc_sockettype_tcp, socketp=0x7fffea8431a8) at socket.c:
# 0x0000000000413a62 in add_listener (cp=0x7ffff7faf038, listenerp=0x7fffec787aa0, control=0x7ffff7fcfb38,
config=0x7ffff7fcf550, addr=0x7fffec787990, aclconfctx=0x7ffff7fa3070, socktext=0x7fffec787a40 "0.0.0.0#953",
type=isc_sockettype_tcp) at controlconf.c:
# 0x0000000000413fd2 in ns_controls_configure (cp=0x7ffff7faf038, config=0x7ffff7fcf550, aclconfctx=0x7ffff7fa3070)
at controlconf.c:
# 0x0000000000438916 in load_configuration (filename=0x7fffffffe850 "/var/named/named.conf", server=0x7ffff7fae010,
first_time=isc_boolean_true) at server.c:
# 0x0000000000439fdf in run_server (task=0x7ffff7fba010, event=0x0) at server.c:
# 0x00000000005b3b15 in dispatch (manager=0x7ffff7fa5010) at task.c:
# 0x00000000005b3da1 in run (uap=0x7ffff7fa5010) at task.c:
# 0x0000003817a07a51 in start_thread () from /lib64/libpthread.so.
# 0x00000038176e896d in clone () from /lib64/libc.so.

socket在socketmgr中的存储:

sock->manager->fds[sock->fd] = sock;
sock->manager->fdstate[sock->fd] = MANAGED;

3、epoll监听套接字和管道:

几个重点函数:

  • watch_fd            给select或epoll添加监听描述符;
  • unwatch_fd        去除select或epoll中的监听描述符;
  • select_poke        写管道,通知select/epoll监听线程给select或epoll添加监听描述符;
  • select_readmsg   读管道,在wakeup_socket函数(调用watch_fd)之前调用;

epoll既可以监听管道,又可以监听套接字。bind9的套接字监听控制管道在管道建立的时候就直接加入到监听列表中了,具体栈过程如下:

#  watch_fd (manager=0x7ffff7fa9010, fd=, msg=-) at socket.c:
# 0x00000000005c5947 in setup_watcher (mctx=0x8742d0, manager=0x7ffff7fa9010) at socket.c:
# 0x00000000005c5f2a in isc__socketmgr_create2 (mctx=0x8742d0, managerp=0x8701f8, maxsocks=) at socket.c:
# 0x000000000041919e in create_managers () at ./main.c:
# 0x0000000000419727 in setup () at ./main.c:
# 0x0000000000419a2b in main (argc=, argv=0x7fffffffe5c8) at ./main.c:

如果有需要监听的套接字,可以通过写上面的管道, 使用管道可以避免线程同步的麻烦。

#  select_poke (mgr=0x7ffff7fa9010, fd=, msg=-) at socket.c:
# 0x00000000005c68dd in socket_recv (sock=0x7ffff7fd6010, dev=0x7fffeaed8148, task=0x7ffff7fba9b0, flags=)
at socket.c:
# 0x00000000005c6f61 in isc__socket_recv2 (sock0=0x7ffff7fd6010, region=0x7ffff0f90d10, minimum=,
task=0x7ffff7fba9b0, event=0x7fffeaed8148, flags=) at socket.c:
# 0x000000000040cf58 in client_udprecv (client=0x7fffe4004c40) at client.c:
# 0x000000000040877a in client_start (task=0x7ffff7fba9b0, event=0x7fffe40050e8) at client.c:
# 0x00000000005b3b15 in dispatch (manager=0x7ffff7fa5010) at task.c:
# 0x00000000005b3da1 in run (uap=0x7ffff7fa5010) at task.c:
# 0x0000003817a07a51 in start_thread () from /lib64/libpthread.so.
# 0x00000038176e896d in clone () from /lib64/libc.so.

在socket_recv函数中有这样的代码:

/*
* Enqueue the request. If the socket was previously not being
* watched, poke the watcher to start paying attention to it.
*/
if (ISC_LIST_EMPTY(sock->recv_list) && !sock->pending_recv)
select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
ISC_LIST_ENQUEUE(sock->recv_list, dev, ev_link);

用于把client的按读事件的调度方式转化为epoll按文件描述符的调度方式(一个套接字可以有很多的读事件)。

在internal_recv()(internal_recv函数后面会讲到)函数中有如下代码:

poke:
if (!ISC_LIST_EMPTY(sock->recv_list))
select_poke(sock->manager, sock->fd, SELECT_POKE_READ);

通过这两处的写管道配合,即使没有用锁,也可以完美线程同步。

写管道之后,watcher线程再读管道,具体栈过程如下:

#  watch_fd (manager=0x7ffff7fa9010, fd=, msg=-) at socket.c:
# 0x00000000005bf14b in wakeup_socket (manager=0x7ffff7fa9010, fd=, msg=-) at socket.c:
# 0x00000000005c554e in process_ctlfd (manager=0x7ffff7fa9010) at socket.c:
# 0x00000000005c549f in process_fds (manager=0x7ffff7fa9010, events=0x7ffff7faa010, nevents=) at socket.c:
# 0x00000000005c5696 in watcher (uap=0x7ffff7fa9010) at socket.c:
# 0x0000003817a07a51 in start_thread () from /lib64/libpthread.so.
# 0x00000038176e896d in clone () from /lib64/libc.so.

select_readmsg会在watch_fd函数之前调用,用于读管道。

select/epoll监听线程(watcher函数)是一个快速精悍线程,也就是说判断到可读可写状态后的读写操作不是在此函数完成的,所以在epoll之后要及时把相关套接字从epoll中监听列表中剔除(调用unwatch_fd函数),只有当实际接受函数完成或等待读事件耗尽才会再次加进去。从列表中剔除的同时发送读事件,task调度线程会通知实际的读函数去完成读任务。

socket_recv、dispatch_recv、internal_recv三个函数的关系:

  • socket_recv读套接字,如果暂时没有内容,把读事件加入套接字的读事件列表,有必要的话还把套接字加入epoll监听列表;
  • dispatch_recv由epoll监听线程调用,但它并不真正执行读任务,而是通过发送读时间通知task调用internal_recv;
  • internal_recv显然就是那个干苦力的;

[DNS-BIND]网络初始化的更多相关文章

  1. nginx源码分析之网络初始化

    nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...

  2. 第7章 DNS & bind从基础到深入

    本文目录: 7.1 DNS必懂基础 7.1.1 域的分类 7.1.2 主机名.域名.FQDN 7.1.3 域的分层授权 7.1.4 DNS解析流程 7.2 DNS术语 7.2.1 递归查询和迭代查询 ...

  3. DNS(bind)服务器安装和配置

    一.前言 DNS 域名系统(英文:Domain Name System,缩写:DNS)是因特网的一项服务.它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网.DNS使用TCP ...

  4. 金蝶盘点机条码数据採集器PDA,WIFI已经连接,可是PDA应用程序还是网络初始化不成功?

    PDA任务栏里显示了小电脑.小电脑也是绿色的,为什么PDA还是网络初始化不成功呢? 1.须要检查下server的[PDA后台服务程序]是否打开?假设没有打开请打开[PDA后台服务程序]. 2.须要检查 ...

  5. 为linux dns (bind named)服务器配置 单独的笔记

    注意: 当在把 named.ca文件下载好13个根dns服务器的 全球记录后, 就不再需要别的 dns服务器来辅助获得了. 只要把所有 本地服务器 不能解析的请求, 都发送到 . 点根去就行了, 所以 ...

  6. dns bind配置教程

    实验环境 三台centos7虚拟机,一台ip为192.168.52.130,一台为192.168.52.131,最后一台为192.168.52.132 安装bind 使用yum -y insall b ...

  7. DNS BIND之dnssec安全介绍

    Domain Name System Security Extensions (DNSSEC)DNS安全扩展,是由IETF提供的一系列DNS安全认证的机制(可参考RFC2535).它提供了一种来源鉴定 ...

  8. DNS bind子域授权安装

    失败经验:rhel 6.x bind 9.8,两台做子域授权,最后失败.原因不详. 改用rhel 5.5, bind 9.3,同样的配置,就成功了.具体记录一下9.3的配置. 安装:采用安装RHEL时 ...

  9. DNS Bind服务配置解析

    DNS域名解析服务(Domain Name System)是用于解析域名与IP地址对应关系的服务,功能上可以实现正向解析与反向解析: 一.DNS服务器工作模式分类: 1.主服务器:在特定区域内具有唯一 ...

  10. DNS/BIND in Debian

    Debian official document:http://www.debian.org/doc/manuals/network-administrator/ch-bind.html Buildi ...

随机推荐

  1. hdu4449Building Design(三维凸包+平面旋转)

    链接 看了几小时也没看懂代码表示的何意..无奈下来问问考研舍友. 还是考研舍友比较靠谱,分分钟解决了我的疑问. 可能三维的东西在纸面上真的不好表示,网上没有形象的题解,只有简单"明了&quo ...

  2. PHPStorm技巧篇 -- 观感优化

    (1)设置默认显示行号 (2)设置自动换行 (3)去除代码下划线(拼写检测) 优化说明:自动换行和显示行号字面意思很好理解,下划线说明一下,phpstorm默认对代码进行拼写校验,即对于不符合英文单词 ...

  3. 使用Memcache缓存mysql数据库操作的原理和缓存过程浅析

    转载自脚本之家 http://www.jb51.net/article/51831.htm  作者:忙碌的松鼠 对于大型网站如facebook,ebay等网站,如果没有Memcache做为中间缓存层, ...

  4. Lua 与 Redis

    Lua 与 Redis 标签: Java与NoSQL 从 2.6版本 起, Redis 开始支持 Lua 脚本 让开发者自己扩展 Redis - 案例-实现访问频率限制: 实现访问者 $ip 在一定的 ...

  5. .net预览功能

    1.把需要预览的文件格式转换为pdf 2.下载pdttoswf软件 3.实现预览swf功能 ok excel转pdf时会出现乱掉的问题.是excel文件的问题.调整excel文件的格式即可.

  6. linux 挂载光盘:mount: you must specify the filesystem type

    尝试挂载光盘镜像时出现mount: you must specify the filesystem type 使用-t auto -t iso9660 或不加参数都搞不定,最后在以下链接找到解决办法: ...

  7. jmeter for循环嵌套if学习2

    if语句中勾选Evaluate选项,每执行一句都会判断result的值是否为true. 执行结果: three没有执行,到debug时变量的值变成tom了

  8. html/css小练习2

    效果图:

  9. 转载:[AngularJS系列] 那伤不起的provider们啊~ (Provider, Value, Constant, Service, Factory, Decorator)

    来源:http://hellobug.github.io/blog/angularjs-providers/ 用AngularJS做项目,但凡用过什么service啊,factory啊,provide ...

  10. Java Js实现导出csv

    $.ajax({ type: 'GET', async: false, url: '../../api/screening/exportTable?seriesIndex=' + param.seri ...