本文簡要介紹一下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_inte***ce_listenudp
其中ns_inte***ce_listenudp的作用是在給定的ip位址和埠上監聽udp事件:
首先,呼叫
dns_dispatch_getudp()從inte***ce 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
2
3
4
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);來建立執行緒監聽這個inte***ce 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原始碼分析奠基
因為從事的是dns方面的工作,而且也很想學習高效能伺服器的知識,所以學習bind9的實現既能兼顧工作又可以學到高效能伺服器的知識。一是市面上bind9原始碼分析的資料太少了,而且 量又很大,所以對於像我這樣的新手來說入門門檻實在太高,所以想把自己的總結分享出來,幫助那些新人。by the way,我...
bind9原始碼分析 檢視A記錄的資料組織
方法 gdb除錯時,如下可以看到某一node節點資料,gdb p rdatasetheader t dns rbtdb t dns zone t named g server viewlist head zonetable table root data db tree root down data...
BIND9原始碼學習筆記1 gdb除錯篇
學習bind9原始碼之前,首先要知道如何用gdb來除錯bind。bind9的原始碼我是先看 弄懂它的架構,像什麼event drive,epoll等,再去看它的業務流程。看業務流程的時候要追蹤它的資料流和處理過程,所以用gdb比較好,當然自己加日誌再結合bind9自有的日誌也不是不 行,只是覺得這樣...