本文简要介绍一下BIND9中的UDP数据处理,包括如何创建socket、设置什么socket参数、多线程环境中如何让多个线程读取53端口的数据等等。

BIND9的架构采用event-driven和task-based。对于像TCP这样的事件采用event-driven来等待读写时间,而在多线程方面,采用task-based的方式,服务器启动时由task_manager创建一系列干活的线程task(CPU个数个),然后外部的用户通过调用isc_task_send函数将事件挂到task_manager的事件队列中,各线程(task)从这个事件队列中获得要干的活,开始干活。

对于UDP而言,BIND9的做法是在主进程中创建好UDP socket,然后各个线程都在这个fd上通过recvmsg来收取消息并处理(由于recvmsg是线程安全的,所以多线程环境中可以这样用而不用加锁)

关键流程如下所示:

1, 主进程:ns_interface_listenudp <--ns_interface_setup <-- do_scan <-- ns_interfacemgr_scan0 <-- ns_interfacemgr_scan <-- scan_interfaces <--load_configuration <-- run_server <-- ns_server_create <-- setup <-- main

其中ns_interface_listenudp的作用是在给定的IP地址和端口上监听UDP事件:

 首先,调用dns_dispatch_getudp()从interface manager中获取到udpdispatch(如果没有,就创建一个),其中在创建udpdispatch的dispatch_createudp函数中:
   a, 会调用get_udpsocket()创建新的isc_socket_t对象。get_udpsocket()中关键的是open_socket(sockmgr, localaddr,ISC_SOCKET_REUSEADDRESS, &sock)函数,它创建一个socket,并调用bind绑定IP地址和端口。关键步骤是:

  1),调用socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);创建socket.
2),调用 flags = fcntl(fd, F_GETFL, 0); flags |= PORT_NONBLOCK; ret = fcntl(fd, F_SETFL, flags);将socket设置为非阻塞模式
3),调用setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on))设置套接字选项
4),调用bind(sock->fd, &sockaddr->type.sa, sockaddr->length) 为该socket绑定IP地址和端口
 
    b, socket创建好,bind好之后。分配64个task(这些task存在dispatch->task[64]数组中),然后为dispatch->ctlevent分配事件,它调用distroy_disp来销毁一个dispatch(当然其中会调用closesocket来关闭一个socket).
 
  2,通过getudp获取到udpdispatch之后,就调用ns_clientmgr_createclients(ifp->clientmgr, ns_g_cpus, ifp, ISC_FALSE);来创建线程监听这个interface ifp了:
      创建ns_g_cpu个client,然后调用ev = &client->ctlevent;  isc_task_send(client->task, &ev);开始干client_start活
     其中创建client的时候,client->sendevent干client_senddone活;  client->recvevent干client_request活; client->ctlevent干client_start活
 
3, client_start
       对于UDP,执行client_udprecv()函数,client_udprecv的核心是执行isc_socket_recv2函数,isc_socket_recv2的核心是执行socket_recv();socket_recv的核心是doio_recv()。
      doio_recv()中就是recvmsg()系统调用。

工作线程

上面的isc_task_send(client->task, &ev)被调用后,主进程就把任务丢给了工作线程去做。

示意图如下所示:

从上图中可以看到,当线程通过recvmsg接收到数据后会交给队列中的线程执行client_request()函数;client_request就是解包处理DNS请求。

如果线程通过recvmsg没有接收到数据,则将这个fd加入到epoll的监听队列中(BIND9有一个单独的线程执行epoll循环),当这个fd上有读事件的时候,epoll线程会调用internal_recv()处理UDP数据,internal_recv的核心依然是doio_recv函数。

BIND9源码分析之UDP数据处理的更多相关文章

  1. Nginx学习笔记(四) 源码分析&socket/UDP/shmem

    源码分析 在茫茫的源码中,看到了几个好像挺熟悉的名字(socket/UDP/shmem).那就来看看这个文件吧!从简单的开始~~~ src/os/unix/Ngx_socket.h&Ngx_s ...

  2. BIND9源码分析之acl 的实现

    BIND配置中一大堆一大堆的acl,什么allow-query, allow-recursion, allow-update还有view的match-clients等等等等. acl中的主要存储的就是 ...

  3. BIND9源码分析之 多个view的情况下如何做dynamic update

    BIND中view的存在提供了一种较好的智能DNS方案,BIND可以根据用户的来源IP为其返回不同的Resource Record. 但是关于DNS动态更新的RFC2136中并没有提及view(vie ...

  4. 66、Spark Streaming:数据处理原理剖析与源码分析(block与batch关系透彻解析)

    一.数据处理原理剖析 每隔我们设置的batch interval 的time,就去找ReceiverTracker,将其中的,从上次划分batch的时间,到目前为止的这个batch interval ...

  5. Duilib源码分析(六)整体流程

    在<Duilib源码分析(一)整体框架>.<Duilib源码分析(二)控件构造器—CDialogBuilder>以及<Duilib源码分析(三)XML解析器—CMarku ...

  6. jQuery源码分析系列(36) : Ajax - 类型转化器

    什么是类型转化器? jQuery支持不同格式的数据返回形式,比如dataType为 xml, json,jsonp,script, or html 但是浏览器的XMLHttpRequest对象对数据的 ...

  7. 介绍开源的.net通信框架NetworkComms框架 源码分析

    原文网址: http://www.cnblogs.com/csdev Networkcomms 是一款C# 语言编写的TCP/UDP通信框架  作者是英国人  以前是收费的 售价249英镑 我曾经花了 ...

  8. 《深入理解Spark:核心思想与源码分析》(前言及第1章)

    自己牺牲了7个月的周末和下班空闲时间,通过研究Spark源码和原理,总结整理的<深入理解Spark:核心思想与源码分析>一书现在已经正式出版上市,目前亚马逊.京东.当当.天猫等网站均有销售 ...

  9. 《深入理解Spark:核心思想与源码分析》(第2章)

    <深入理解Spark:核心思想与源码分析>一书前言的内容请看链接<深入理解SPARK:核心思想与源码分析>一书正式出版上市 <深入理解Spark:核心思想与源码分析> ...

随机推荐

  1. Additive属性动画

    Additive属性动画 参考 http://ronnqvi.st/multiple-animations/ 效果 源码 https://github.com/YouXianMing/Animatio ...

  2. [翻译] 极具动感的 FRDLivelyButton

    FRDLivelyButton https://github.com/sebastienwindal/FRDLivelyButton FRDLivelyButton is a simple UIBut ...

  3. C++ 转型动作 尽量避免 以及 那些意想不到的威胁

    看完EffectiveC++的关于转型的章节,顿时认为周围的代码都处在悬崖边上~~ C的旧式转型:inta = 10; double b = (double)a; 对于C++的四种转型函数, cons ...

  4. 常用数学函数篇abs acos asin atan ceil cos exp frexp ldexp log pow sin sinh sqrt tan tanh

    abs(计算整型数的绝对值) 相关函数 labs, fabs 表头文件 #include<stdlib.h> 定义函数 int abs (int j) 函数说明 abs()用来计算参数j的 ...

  5. 在Java Web程序中使用Hibernate

    在Java Web程序中使用Hibernate与普通Java程序一样.本文中将使用Servlet和JSP结合Hibernate实现数据库表的增删改查操作. Web程序中,hibernate.cfg.x ...

  6. Copy List with Random Pointer leetcode java

    题目: A linked list is given such that each node contains an additional random pointer which could poi ...

  7. vue-router路由模式详解

    一.路由模式解析 要讲vue-router的路由模式,首先要了解的一点就是路由是由多个URL组成的,使用不同的URL可以相应的导航到不同的位置. 如果有进行过服务器开发或者对http协议有所了解就会知 ...

  8. IE11与Cognos怪谈

    想必大家都知道高版本的IE运行Cognos相关组件的时候要设置兼容性,安全级别相对调低等设置.但是升级了win10系统后,默认的IE版本是IE11的,装了Cognos10.2.1之后,进行了一个常规的 ...

  9. 通过page页面与portlet的结合实现报表的局部刷新

    场景:系统已经存在两个报表,报表A与B,A与B之间可以通过省份进行追溯. 如下图:点击 报表[销售数据按区域]中的北京市 追溯到报表[销售数据按省份] 需求:让上面的操作在一个page里面刷新,实现页 ...

  10. PreferenceScreen的应用

    PreferenceScreen preference是偏好.首选的意思,PreferenceScreen个人翻译成 "偏好显示",明确这个意思就好.就是说依据特点灵活的定义显示内 ...