• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            Benjamin

            靜以修身,儉以養德,非澹薄無以明志,非寧靜無以致遠。
            隨筆 - 397, 文章 - 0, 評論 - 196, 引用 - 0
            數據加載中……

            bind源碼解析(一)

              Bind是一款開放源碼的DNS服務器軟件,Bind由美國加州大學Berkeley分校研發和維護的,全名為Berkeley Internet Name Domain他是目前世界上使用最為廣泛的DNS服務器軟件,支持各種unix平臺和windows平臺。官方網站:http://www.bind.com/

            下面介紹一下Bind軟件的主要的socket處理模塊:
            Bind
            業務處理主要要關注一個run函數和isc_app_run函數,前者是線程函數,相當于一個消息泵,這個for循環作用通過管道發送事件,這個事件在到task里的run中被處理,如此反復和windows編程中的消息循環類似;

            Bind中的socket采用的是epoll模型,在main.c中的setup函數里的result = create_managers()->result = isc_socketmgr_create2(ns_g_mctx, &ns_g_socketmgr, maxsocks)-> setup_watcher;創建epoolif(isc_thread_create(watcher, manager, &manager->watcher) != ISC_R_SUCCESS) 啟動watcher這個線程函數process_fds來處理epoll,具體的處理函數是process_fd,根據不同的事件來執行dispatch_accept(sock); dispatch_recv(sock); dispatch_connect(sock); dispatch_send(sock);這幾個函數最后執行的都是isc_task_send(它的作用是將event加到task隊列中)

            main函數中,setup創建進程必要的服務,setup里比較重要的函數是create_managersns_server_createns_server_create主要是對一些結構體中的函數指針賦值還有用到的數據結構分配內存,create_managers啟動各種線程;

            isc_app_run則是見將on-run事件(通過管道)加入到任務隊列中,最終執行的是isc__task_sendanddetach。在ns_server_create中的CHECKFATAL(isc_app_onrun(ns_g_mctx, server->task, run_server, server),"isc_app_onrun")里的ISC_LIST_APPEND(isc_g_appctx.on_run, event, ev_link)比較關鍵,將on-run事件到鏈表中,這個鏈表在isc_app_run里的for循環中被遍歷;

            Socket的初始化:

            setup(void)-> create_managers->isc__socketmgr_create2函數中:
            manager->common.methods = &socketmgrmethods;將函數指針賦值。ns_server_create(ns_g_mctx, &ns_g_server)
            CHECKFATAL(isc_app_onrun(ns_g_mctx, server->task, run_server, server),"isc_app_onrun");實際執行的是run_server函數
            load_configuration->scan_interfaces(server, ISC_TRUE)->ns_interfacemgr_scan(server->interfacemgr, verbose)->ns_interfacemgr_scan0(mgr, NULL, verbose)-> do_scan->ns_interface_setup->if (accept_tcp == ISC_TRUE) {result = ns_interface_accepttcp(ifp);->isc_socket_create->manager->methods->socketcreate(manager, pf, type, socketp)這句代碼會調用上面賦給的函數地址(socketmgrmethods),將調用socketmgrmethodsisc__socket_create函數。前面闡述的是有關tcp的初始化,下面是udp的初始化:

            do_scan->ns_interface_setup->ns_interface_listenudp->ns_clientmgr_createclients->client_create->
            clclient->sendevent = (isc_socketevent_t *)
                   isc_event_allocate(client->mctx, client,
                        ISC_SOCKEVENT_SENDDONE,
                        client_senddone, client,
                        sizeof(isc_socketevent_t));
            client->recvevent = (isc_socketevent_t *)
                   isc_event_allocate(client->mctx, client,
                        ISC_SOCKEVENT_RECVDONE,
                        client_request, client,
                        sizeof(isc_socketevent_t));

            主要功能就是賦值ISC_EVENT_INIT(event, size, 0, NULL, type, action, deconst_arg,sender, destroy, mctx);active函數指針賦值為client_request,即在這里給UDP的處理函數賦值(接收);發送同樣如此:這樣每進來一次udp就查詢一次,,會在task的run函數里執行active指針函數,進而調用這個client_request

            switch (client->message->opcode) {
             case dns_opcode_query:
                          CTRACE("query");
                          ns_query_start(client);
                          break;
                   case dns_opcode_update:
                          CTRACE("update");
                          ns_client_settimeout(client, 60);
                          ns_update_start(client, sigresult);
                          break;
                   case dns_opcode_notify:
                          CTRACE("notify");
                          ns_client_settimeout(client, 60);
                          ns_notify_start(client);
                          break;

                   case dns_opcode_iquery:
                          CTRACE("iquery");
                          ns_client_error(client, DNS_R_NOTIMP);
                          break;
                   default:
             
                          CTRACE("unknown opcode");
                         ns_client_error(client, DNS_R_NOTIMP);
                   }

             

            Sockettask的關聯(和一些關鍵性代碼的說明):

            1isc__task_create(isc_taskmgr_t *manager0, unsigned int quantum,isc_task_t **taskp)—創建ns_g_taskmgr,實參:ns_g_mctx, ns_g_cpus, 0, &ns_g_taskmgr
             
            /*分配內存*/manager = isc_mem_get(mctx, sizeof(*manager));返回的是ret = ctx->freelists[new_size];(ctx->memalloc)(ctx->arg, size);前者是鏈表的最后,后在則是分配的內存的起始位置。
            manag的數據類型是isc__taskmgr_tctxisc__mem類型,ctx->freelistelement **           freelistselement則是typedef struct element element;
            struct element { 
                 
            element *            next;
            };

            //初始化條件變量(linux系統的函數) 一旦其它的某個線程改變了條件變量,它將通知相應的條件變量喚醒一個或多個正被此條件變量阻塞的線程。這些線程將重新鎖定互斥鎖 并重新測試條件是否滿足。一般說來,條件變量被用來進行線程間的同步。

            if (isc_condition_init(&manager->work_available) != ISC_R_SUCCESS) {
                          UNEXPECTED_ERROR(__FILE__, __LINE__,
                                         "isc_condition_init() %s",
                                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
                                                      ISC_MSG_FAILED, "failed"));
                          result = ISC_R_UNEXPECTED;
                          goto cleanup_threads;
                   }

                   /*初始化條件變量*/
                   if (isc_condition_init(&manager->exclusive_granted) != ISC_R_SUCCESS) {
                          UNEXPECTED_ERROR(__FILE__, __LINE__,
                                         "isc_condition_init() %s",
                                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
                                                      ISC_MSG_FAILED, "failed"));
                          result = ISC_R_UNEXPECTED;
                          goto cleanup_workavailable;
                   }

             

            /*啟線程*/
                   for (i = 0; i < workers; i++) {
                          if (isc_thread_create(run, manager,
                                           &manager->threads[manager->workers]) ==
                              ISC_R_SUCCESS) {
                                 manager->workers++;
                                 started++;
                          }
                   }

            /*設置并發線程*/
            isc_thread_setconcurrency(workers);
            /*附加到特定的內存塊上*/
            isc_mem_attach(mctx, &manager->mctx);muct的值賦給&manager->mctx
            最后啟動線程。重點說明一下這個run線程函數,這個線程函數使用來處理task的。run(void *uap) {

            …………………………………………………………………….
                   isc__taskmgr_t *manager = uap;
                   dispatch(manager);windowsDispatchMessage類似分發消息

            ……………………………………………………………………..
                   return ((isc_threadresult_t)0);

            }

            static void dispatch(isc__taskmgr_t *manager)里面有三個while循環
            //判斷(manager)->exiting && (manager)->tasks. .head == NULL
            while (!FINISHED(manager))
            while ((EMPTY(manager->ready_tasks) ||manager->exclusive_requested) &&!FINISHED(manager)) // 判斷(manager->ready_tasks).head ==NULL
            {、
            XTHREADTRACE(isc_msgcat_get(isc_msgcat,ISC_MSGSET_GENERAL,ISC_MSG_WAIT, "wait"));
            WAIT(&manager->work_available, &manager->lock);
            //實際執行的是isc_condition_wait((&manager->work_available), (&manager->lock)) == ISC_R_SUCCESS);-----------------> (pthread_cond_wait((&manager->work_available), &((&manager->lock)->mutex)) == 0,這里用來發信號,對互斥量加以保護,線程釋放互斥量,等待其他線程發給該條件變量的信號(喚醒一個等待者)或廣播該條件變量(喚醒所有等待者)。當等待條件變量時,互斥量必須始終為釋放的,這樣其他線程才有機會鎖住互斥量,修改條件變量。當線程從條件變量等待中醒來時,它重新繼續鎖住互斥量,對臨界資源進行處理。
            XTHREADTRACE(isc_msgcat_get(isc_msgcat,ISC_MSGSET_TASK,ISC_MSG_AWAKE, "awake"));
            }
            task = HEAD(manager->ready_tasks);
            if (task != NULL) {
            task->state = task_state_running;
                               XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
                                                   ISC_MSG_RUNNING, "running"));
                               isc_stdtime_get(&task->now);
            //遍歷鏈表
                               do {
                                      if (!EMPTY(task->events)) {
                                             event = HEAD(task->events);
                                             DEQUEUE(task->events, event, ev_link);
             

                                             /**執行事件消息處理  */
            .........................................................

            if (event->ev_action != NULL) {
            UNLOCK(&task->lock);
             (event->ev_action)(   (isc_task_t *)task, event);
            LOCK(&task->lock);   
                                         
            }
                       
             
            dispatch_count++;
             } if (task->references == 0 && EMPTY(task->events) &&!TASK_SHUTTINGDOWN(task)) { isc_boolean_t was_idle;

            /*在這個任務里沒有引用沒有待定的事件,這意味者不會有實際的事件(動作)發生,初始化關機以防止成為一個廢止(狀態)。替代"if EMPTY(task->events)"的原因:如果發送沒有關機事件,將派發一個結束任務;如果沒有派發關機事件,(總是)希望任務的總量是實際中(任務的總量)*/
             was_idle = task_shutdown(task);                                
            INSIST(!was_idle);
             } 

                                      if (EMPTY(task->events)) {                       
                                         XTRACE(isc_msgcat_get(isc_msgcat,
                                                                 ISC_MSGSET_TASK,
                                                                 ISC_MSG_EMPTY,
                                                                 "empty"));
                                             if (task->references == 0 &&
                                                 TASK_SHUTTINGDOWN(task)) {
                                                   /*The task is done */
                                                   XTRACE(isc_msgcat_get(
                                                                  isc_msgcat,
                                                                  ISC_MSGSET_TASK,
                                                                  ISC_MSG_DONE,
                                                                 "done"));
                                                    finished = ISC_TRUE;
                                                    task->state = task_state_done;
                                             } else
                                                    task->state = task_state_idle;
                                             done = ISC_TRUE;
                                      } else if (dispatch_count >= task->quantum) {

            /*(任務)總量用完,但是還有更多的work在做,將重新排列放到在準備隊列后。不必檢查總量直到至少派發一個事件,因此最小數是1*/                                 XTRACE(isc_msgcat_get(isc_msgcat,
                                                                 ISC_MSGSET_TASK,
                                                                 ISC_MSG_QUANTUM,
                                                                 "quantum"));
                                             task->state = task_state_ready;
                                             requeue = ISC_TRUE;
                                             done = ISC_TRUE;
                                      }
                               } while (!done); 初始化是ISC_FALSE
                   ………

            } 

            注意:上面處理的是ns_g_taskmgr里的task

             

            2isc__socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp,unsigned int maxsocks)//創建ns_g_socketmgr
            實參:ns_g_mctx, &ns_g_socketmgr, maxsocks
            isc__socketmgr_t *manager;
            *managerp = (isc_socketmgr_t *)socketmgr;//初始化 

            manager = isc_mem_get(mctx, sizeof(*manager));//分配內存manger的各個成員變量和方法賦值;

            ................................................
            //
            初始化manager->shutdown_ok—條件變量,和互斥對象配合使用在多線程編程中。
            if (isc_condition_init(&manager->shutdown_ok) != ISC_R_SUCCESS) {
                          UNEXPECTED_ERROR(__FILE__, __LINE__,
                                         "isc_condition_init() %s",
                                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
                                                      ISC_MSG_FAILED, "failed"));
                          result = ISC_R_UNEXPECTED;
                          goto cleanup_lock;
                   }

            //創建管道-----epoll模型中使用
            if (pipe(manager->pipe_fds) != 0) {
                          isc__strerror(errno, strbuf, sizeof(strbuf));
                          UNEXPECTED_ERROR(__FILE__, __LINE__,
                                         "pipe() %s: %s",
                                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,\
                                                      ISC_MSG_FAILED, "failed"),
                                         strbuf);
                          result = ISC_R_UNEXPECTED;
                          goto cleanup_condition;
                   }

            //設置EPOLL中的事件和文件描述的關聯
            result = setup_watcher(mctx, manager);這個函數實際上執行的是epoll_ctl(manager->epoll_fd, EPOLL_CTL_ADD, fd, &event)
            if (isc_thread_create(watcher, manager, &manager->watcher) !=ISC_R_SUCCESS)//啟動線程,實際執行的是cc = epoll_wait(manager->epoll_fd, manager->events,
            manager->nevents, -1);開始監聽管道里的事件,如果需要處理就處理。

            posted on 2010-12-20 21:44 Benjamin 閱讀(4034) 評論(3)  編輯 收藏 引用 所屬分類: linux

            評論

            # re: bind源碼解析(一)  回復  更多評論   

            When you are in a not good position and have no money to move out from that, you would require to take the <a href="http://bestfinance-blog.com/topics/home-loans">home loans</a>. Just because that will help you unquestionably. I get short term loan every time I need and feel good because of that.
            2011-09-08 14:39 | CAMERONMeredith19

            # re: bind源碼解析(一)  回復  更多評論   

            Do you see that you do great investigation just about this good post. Continue performing that! Students buy essay just about this opting for the term paper writing services.
            2011-10-07 06:25 | buy essays

            # re: bind源碼解析(一)  回復  更多評論   

            Tha’s really payless to receive hot enough fact referring to this good topic. But sometimes students switch on the personal computer and buy research paper and everybody could have the assistance of the high quality custom essays writing corporations to buy an essay fast.
            2011-10-09 02:18 | buy research papers
            久久99久久99小草精品免视看| 国产福利电影一区二区三区久久老子无码午夜伦不 | 久久99热这里只有精品66| 日韩美女18网站久久精品| 精品综合久久久久久97| 久久精品无码专区免费青青| 久久成人国产精品一区二区| 中文字幕乱码久久午夜| 999久久久免费国产精品播放| 久久免费观看视频| 久久精品人人槡人妻人人玩AV | 久久精品国产99国产精品导航 | 久久精品国产精品亚洲下载| 国产毛片欧美毛片久久久| 国产99久久久国产精免费| 国产69精品久久久久久人妻精品| 一本大道久久a久久精品综合| 精品久久久中文字幕人妻| 久久久久久亚洲精品不卡| 91精品国产91久久| 囯产极品美女高潮无套久久久| 久久se精品一区精品二区国产| 狼狼综合久久久久综合网| 一本大道久久东京热无码AV| 国产欧美久久久精品| 久久综合国产乱子伦精品免费| 一本久久a久久精品综合香蕉| 久久福利青草精品资源站免费| 伊人久久综合无码成人网| 久久婷婷人人澡人人| 久久激情五月丁香伊人| 久久91精品国产91久久小草| 国产精品免费看久久久| 久久国产热精品波多野结衣AV| 色播久久人人爽人人爽人人片AV| 久久无码国产| 久久人妻少妇嫩草AV蜜桃| 久久精品三级视频| 青青草国产97免久久费观看| 亚洲午夜久久久| 精品一二三区久久aaa片|