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. php使用PDO连接mysql数据库

    <?php $dsn='mysql:host=localhost;dbname=mssc'; $user='root'; $password=''; $status=1; try { $sql= ...

  2. YYYY-mm-dd HH:MM:SS

    备忘:YYYY-mm-dd HH:MM:SS部分解释 d               月中的某一天.一位数的日期没有前导零.    dd             月中的某一天.一位数的日期有一个前导零 ...

  3. C#操作SQL Server数据库

    http://www.cnblogs.com/rainman/archive/2012/03/13/2393975.html

  4. centos 忘记密码

    装了个  centos 6.8  安装的时候 要输入 新用户和密码 用 新的用户密码 进去后 各种没权限  重新修改 root 密码   一切OK 步骤 1.重新启动Centos,在启动过程中,长按“ ...

  5. Apache Commons BeanUtils

    http://commons.apache.org/proper/commons-beanutils/javadocs/v1.9.2/apidocs/org/apache/commons/beanut ...

  6. (转)px、em、rem的区别和使用

    国内的设计师大都喜欢用px,而国外的网站大都喜欢用em和rem(国外的大部分网站能够调整的原因在于其使用了em或rem作为字体单位),那么三者有什么区别,又各自有什么优劣呢? 一.px特点 1. IE ...

  7. log4net RemotingAppender 的配置

    Before you even start trying any of the alternatives provided, ask yourself whether you really need ...

  8. Win服务器常用批处理脚本

    oracle数据库备份 先导出数据库,然后执行压缩,将源文件删除,保留压缩文件 exp crm/crm@orcl file=G:\数据库备份\CRM\CRM%DATE%.dmp owner=crm&q ...

  9. 268. Missing Number -- 找出0-n中缺失的一个数

    Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one that is missin ...

  10. 通过php下载文件并重命名

    $filename = dirname(__FILE__) . '/oldfilename.jpg'; $out_filename = 'newfilename.jpg'; if( ! file_ex ...