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. linux下使用fork,exec,waitpid模拟system函数

    代码如下: #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include &l ...

  2. gdb调试基本命令(常用)

    gdb调试命令 1>. 启动gdb gdb 可执行程序的名字 2>. 查看代码 l -- 查看当前文件 -- 默认main函数 2. 查看其它文件: l 文件名:行号, 显示指定行号的上下 ...

  3. guardian keytab生成不了

    vim /var/kerberos/krb5kdc/kadm5.acl 将*e改成* /etc/init.d/kadmin restart 重启kadmin

  4. 小程序 web 端实时运行工具

    微信小程序 web 端实时运行工具 https://chemzqm.github.io/wept/

  5. jQuery 表格删除,添加行

    var colsNum = 4; 1,$(document),ready(function () { $.("#id1").parent().after('<tr class ...

  6. ArcGIS创建tpk切片缓存

    一. 背景知识 1. tpk是什么? 从地图或底图生成切片,并将切片进行打包从而创建单个压缩的 .tpk 文件.切片包(.tpk)是在地图或栅格数据集中能作为 Web 切片或 Web 高程图层发布的一 ...

  7. 再战江湖。vuforia 初试

    AR 里发现一个可用的项目  vuforia,  试着用用. 也是在很久不写博客后(以前全在百度博客上) 再次写

  8. wmic 命令的一个汇总,功能很强大

    获得系统版本信息wmic datafile where Name='c:\\windows\\explorer.exe' get Manufacturer,Version,Filename 获得系统进 ...

  9. SHAREPOINT 2013 列表之间相互关联

    修改内容 1.增加列表设置,隐藏Aid字段操作 SharePoint 列表之间相互关联 例如两张列表之间的父子关系. 思路如下: 列表中新增列表项后会有一个唯一的ID,我们获取到该ID赋予子表即可将两 ...

  10. ios基础篇(二十四)—— 文字、图片的绘制及其自定义Button

    这篇文章我们主要来拿官方的控件来研究一下,我们来仿照官方的控件,自己来实现它提供的控件: 首先来看看基本的图片与文字的绘制,很简单. 一.imageView 所有的视图都是继承自UIView,所以我们 ...