[DNS-BIND]网络初始化
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]网络初始化的更多相关文章
- nginx源码分析之网络初始化
nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...
- 第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 递归查询和迭代查询 ...
- DNS(bind)服务器安装和配置
一.前言 DNS 域名系统(英文:Domain Name System,缩写:DNS)是因特网的一项服务.它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网.DNS使用TCP ...
- 金蝶盘点机条码数据採集器PDA,WIFI已经连接,可是PDA应用程序还是网络初始化不成功?
PDA任务栏里显示了小电脑.小电脑也是绿色的,为什么PDA还是网络初始化不成功呢? 1.须要检查下server的[PDA后台服务程序]是否打开?假设没有打开请打开[PDA后台服务程序]. 2.须要检查 ...
- 为linux dns (bind named)服务器配置 单独的笔记
注意: 当在把 named.ca文件下载好13个根dns服务器的 全球记录后, 就不再需要别的 dns服务器来辅助获得了. 只要把所有 本地服务器 不能解析的请求, 都发送到 . 点根去就行了, 所以 ...
- dns bind配置教程
实验环境 三台centos7虚拟机,一台ip为192.168.52.130,一台为192.168.52.131,最后一台为192.168.52.132 安装bind 使用yum -y insall b ...
- DNS BIND之dnssec安全介绍
Domain Name System Security Extensions (DNSSEC)DNS安全扩展,是由IETF提供的一系列DNS安全认证的机制(可参考RFC2535).它提供了一种来源鉴定 ...
- DNS bind子域授权安装
失败经验:rhel 6.x bind 9.8,两台做子域授权,最后失败.原因不详. 改用rhel 5.5, bind 9.3,同样的配置,就成功了.具体记录一下9.3的配置. 安装:采用安装RHEL时 ...
- DNS Bind服务配置解析
DNS域名解析服务(Domain Name System)是用于解析域名与IP地址对应关系的服务,功能上可以实现正向解析与反向解析: 一.DNS服务器工作模式分类: 1.主服务器:在特定区域内具有唯一 ...
- DNS/BIND in Debian
Debian official document:http://www.debian.org/doc/manuals/network-administrator/ch-bind.html Buildi ...
随机推荐
- startActivity跳转失败而且没有异常信息
startActivity跳转不能显示目标activity的布局(显示空白页),而且没有异常信息 onCreate()方法重写错误 应该重写的是onCreate(Bundle savedInstanc ...
- 反射(Reflection)
反射主要用于在程序运行期间动态解析相关类的类名,命名空间,属性,方法并进行相应操作,以下通过两个简单的例子进行了说明: 示例1:调用程序集内部方法,运行时动态获取相关类的信息,包括类名,命名空间等信息 ...
- web.xml中的contextConfigLocation在spring中的作用
在web.xml中通过contextConfigLocation配置spring, contextConfigLocation参数定义了要装入的 Spring 配置文件.默认会去/WEB-INF/下加 ...
- vue 2.0
vue2.0 据说也出了很久了,博主终于操了一次实刀. 整体项目采用 vue + vue-router + vuex (传说中的vue 全家桶 ),构建工具使用尤大大推出的vue-cli 项目是 ...
- ES6(一)ECMAscript6介绍
nvm-windows Node.js是JavaScript语言的服务器运行环境,对ES6的支持度比浏览器更高.通过Node,可以体验更多ES6的特性.建议使用版本管理工具nvm,来安装Node,因为 ...
- 处理某个json文件的代码
# encoding=utf-8 import json,re with open('E:\\weather53892_20114.json','r') as f: data= f.readlines ...
- python 执行execute遇到的问题
1.如下方式去查询无法查询出结果,但直接在数据库查询中去查询是能查询到结果的,郁闷中,花了很久的时间才知道原来是双引号导致的 把:name="%s" 中的%s前后的双引号去掉就对了 ...
- ArcGIS操作Excel文件没有注册类解决办法
在ArcGIS Desktop中进行表连接时选择了一张excel表,但添加该表时报错: 原因是机器上缺少Office的数据驱动. ArcGIS 支持 : Excel 2003 以及更早版本的 .xls ...
- Android版本
Android自从3.0版本开始引入了Fragment的概念,它可以让界面在平板上更好地展示 Fragment建议继承android.app.Fragment的包,另外support.v4包主要是 ...
- 【思路】-jscode
jscode //1.0 思路 //VH.PutSet(TagFields.PageName, PageName.Index); ...