在上面创建好管理器以后,中间还会有dlz即动态数据的加载,暂且把它们放到后面的部分来讲解,这里重点分析一下server的启动过程,为了和前面socket管理那一块相呼应,所以这里会重点讲一下根socket相关的部分,对于数据部分的加载我会在适当的时候进行分析
重要的数据结构:
1.db的类型,主要有三个
typedef enum {
dns_dbtype_zone = 0, dns_dbtype_cache = 1, dns_dbtype_stub = 3
} dns_dbtype_t;
2.后面多次用到的name
struct dns_name {
unsigned int magic;
unsigned char * ndata;
unsigned int length;
unsigned int labels;
unsigned int attributes;
unsigned char * offsets;
isc_buffer_t * buffer;
}
static dns_name_t root =
{
DNS_NAME_MAGIC,
root_ndata, 1, 1,
DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
root_offsets, NULL,
{(void *)-1, (void *)-1},
{NULL, NULL}
};
ns_server_create(isc_mem_t *mctx, ns_server_t **serverp)
{
//申请一个server,读取的配置文件就会赋值server里面的一些结构
ns_server_t *server = isc_mem_get(mctx, sizeof(*server));
//用默认的值初始化server的结构
result = isc_quota_init(&server->xfroutquota, 10);
result = isc_quota_init(&server->tcpquota, 10);
result = isc_quota_init(&server->recursionquota, 100);
//acl控制列表环境初始化
result = dns_aclenv_init(mctx, &server->aclenv);
{
//初始化ip
result = dns_acl_create(mctx, 0, &env->localhost);
//初始化网段
result = dns_acl_create(mctx, 0, &env->localnets);
}
server->zonemgr = NULL;//区管理器
server->interfacemgr = NULL;
ISC_LIST_INIT(server->viewlist);
server->in_roothints = NULL;
server->blackholeacl = NULL;//acl机制
//注意这里的记录是IN,这就是创建那十三个根管理器
dns_rootns_create(mctx, dns_rdataclass_in, NULL,&server->in_roothints)
{
//创建一个"rbt"类型的db
result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,rdclass, 0, NULL, &db);
{
//注意这是db的方法类型接口
dns_dbimplementation_t *impinfo;
//第一次被初始化的时候,对俩个全局的变量进行赋值,以及将这俩个插入一个全局的链表
static dns_dbimplementation_t rbtimp;
static dns_dbimplementation_t rbt64imp;
static ISC_LIST(dns_dbimplementation_t) implementations;
isc_once_do(&once, initialize)
{
rbtimp.name = "rbt";
rbtimp.create = dns_rbtdb_create;
rbtimp.mctx = NULL;
rbtimp.driverarg = NULL;
ISC_LINK_INIT(&rbtimp, link);
rbt64imp.name = "rbt64";
rbt64imp.create = dns_rbtdb64_create;
rbt64imp.mctx = NULL;
rbt64imp.driverarg = NULL;
ISC_LINK_INIT(&rbt64imp, link);
ISC_LIST_INIT(implementations);
ISC_LIST_APPEND(implementations, &rbtimp, link);
ISC_LIST_APPEND(implementations, &rbt64imp, link);
}
//从列表中找到刚刚创建的那个db,也就是"rbt",这里调用的方法就是上面赋值的dns_rbtdb_create
impinfo = impfind(db_type);
result = ((impinfo->create)(mctx, origin, type, rdclass, argc, argv,impinfo->driverarg, dbp))
{
dns_rbtdb_t *rbtdb = isc_mem_get(mctx, sizeof(*rbtdb));
dns_name_init(&rbtdb->common.origin, NULL);
rbtdb->common.attributes = 0;
//这里依据type赋值不同的创建方法,这里赋值的是zone_method
if (type == dns_dbtype_cache) {
rbtdb->common.methods = &cache_methods;
rbtdb->common.attributes |= DNS_DBATTR_CACHE;
} else if (type == dns_dbtype_stub) {
rbtdb->common.methods = &zone_methods;
rbtdb->common.attributes |= DNS_DBATTR_STUB;
} else
rbtdb->common.methods = &zone_methods;
rbtdb->common.rdclass = rdclass;
//初始化db的三个锁,lock和tree_lock
//赋值结构,如果type是cache的话则不同,初始化db的node_lock
rbtdb->node_lock_count = DEFAULT_NODE_LOCK_COUNT;
rbtdb->node_locks = isc_mem_get(mctx, rbtdb->node_lock_count *sizeof(rbtdb_nodelock_t));
rbtdb->active = rbtdb->node_lock_count
for (i = 0; i < (int)(rbtdb->node_lock_count); i++)
{
//顺次初始化数组里面的每一个锁
}
//创建红黑树,主要就是hashsize和hashtable的创建
result = dns_rbt_create(mctx, delete_callback, rbtdb, &rbtdb->tree);
{
dns_rbt_t *rbt;
rbt->hashtable=rbt->hashsize * sizeof(dns_rbtnode_t *);
}
//把那个全局的dns_name类型的root转变为rbtnode类型赋值,针对不同的zone文件
//每一个zone区都对应一个rbtnode_t的结构
result = dns_rbt_addnode(rbtdb->tree, &rbtdb->common.origin,&rbtdb->origin_node);
{
dns_rbtnode_t * new_current
拷贝name到add_name
dns_name_clone(name, add_name);
result = create_node(rbt->mctx, add_name, &new_current);
{
isc_region_t region;
dns_name_toregion(name, ®ion);
dns_rbtnode_t *node = (dns_rbtnode_t *)isc_mem_get(mctx,sizeof(*node) + region.length + labels)
后面初始化node的结构
}
rbt->nodecount++;
new_current->is_root = 1;
rbt->root = new_current;
*nodep = new_current;
}
}
}
//就是那十三个根服务器
len = strlen(root_ns);
result = dns_db_beginload(db, &callbacks.add,&callbacks.add_private);
dns_master_loadbuffer
eresult = dns_db_endload(db, &callbacks.add_private);
}
//开始绑定重要的事件,这个是reload事件
server->reload_event =isc_event_allocate(ns_g_mctx, server,NS_EVENT_RELOAD,ns_server_reload,server,sizeof(isc_event_t));
//在这个全局的taskmgr中设置server的一个task
isc_task_create(ns_g_taskmgr, 0, &server->task)
//在server的task中设置俩个事件
isc_task_onshutdown(server->task, shutdown_server, server)
isc_app_onrun(ns_g_mctx, server->task, run_server, server)
{
//不是事件添加到全局的on_run列表
ISC_LIST_APPEND(on_run, event, ev_link);
}
//创建zone管理器
dns_zonemgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_timermgr,ns_g_socketmgr, &server->zonemgr)
后面还会初始化server的一些信息
}
该函数执行完成以后会进入到main函数的一个主循环,该循环做的事情就是不断的从on_run事件列表中取出事件然后交给工作线程执行,然后就开始运行run_server了
do
{
result = isc_app_run()
{
//刚刚创建server的时候就把run_server事件添加到了on_run中,因此一旦跑到这里就会开始运行run_server
for (event = ISC_LIST_HEAD(on_run);event != NULL;event = next_event)
{
ISC_LIST_UNLINK(on_run, event, ev_link);
//该task就是ns_g_taskmgr
task = event->ev_sender;
event->ev_sender = NULL;
//交给工作线程去执行,这里是把这个task销毁
isc_task_sendanddetach(&task, &event);
}
}
}while(result!=success)
接下来重点看一下run_server的执行
run_server()
{
ns_server_t *server = (ns_server_t *)event->ev_arg;
//这里开始加载核心的配置文件
char def_conf_fullname[] = “flex”
char local_conf_fullname[] = "flex";
char alc_conf_fullname[] = "flex";
//对三个配置文件的加载以及对某些信息的更新
//对dns消息的处理,创建dns_dispatchmgr_t 并且初始化
dns_dispatchmgr_create(ns_g_mctx, ns_g_entropy, &ns_g_dispatchmgr)
{
dns_dispatchmgr_t *mgr = isc_mem_get(mctx, sizeof(dns_dispatchmgr_t));
//创建三个重要的池子
isc_mempool_create(mgr->mctx, sizeof(dns_dispatchevent_t), &mgr->epool)
}
//对tcp消息的处理
ns_interfacemgr_create(ns_g_mctx, ns_g_taskmgr,ns_g_socketmgr, ns_g_dispatchmgr, &server->interfacemgr)
{
ns_interfacemgr_t *mgr = isc_mem_get(mctx, sizeof(*mgr));
//由它来存储创建好的三个mgr
mgr->taskmgr = taskmgr;
mgr->socketmgr = socketmgr;
mgr->dispatchmgr = dispatchmgr;
ISC_LIST_INIT(mgr->interfaces);
ISC_LIST_INIT(mgr->listenon);
//初始化监听者的结构
result = ns_listenlist_create(mctx, &mgr->listenon4);
//acl
result = dns_aclenv_init(mctx, &mgr->aclenv);
}
//一个默认的配置文件解析器
cfg_parser_create(ns_g_mctx, NULL, &ns_g_parser)
//加载配置文件
load_configuration
//加载区文件
load_zones(server, ISC_FALSE)
ns_os_started();
}
下面用到的重要的数据结构
struct ns_interface {
unsigned int magic; /*%< Magic number. */
ns_interfacemgr_t * mgr; /*%< Interface manager. */
isc_mutex_t lock;
int references; /*%< Locked */
unsigned int generation; /*%< Generation number. */
isc_sockaddr_t addr; /*%< Address and port. */
unsigned int flags; /*%< Interface characteristics */
char name[32]; /*%< Null terminated. */
dns_dispatch_t * udpdispatch; /*%< UDP dispatcher. */
isc_socket_t * tcpsocket; /*%< TCP socket. */
int ntcptarget; /*%< Desired number of concurrent
TCP accepts */
int ntcpcurrent; /*%< Current ditto, locked */
ns_clientmgr_t * clientmgr; /*%< Client manager. */
ISC_LINK(ns_interface_t) link;
};
//这里开始加载配置文件,这个是一个相当重要的函数
//这里小小总结一下这个函数主要做了一些什么,其实主要就是围绕监听的端口展开,注意经过下面的这个函数以后它监听的socket只是由主进程在监听,在执行完成这个函数以后,就会有工作线程执行client_start
首先针对每一个端口会创建一个ns_interface_t *ifp,它会初始化上面的那些结构:具体包括创建ns_clientmgr_t ,并且把它的mgr指向ns_g_taskmgr;赋值ifp->udpdispatch ,ifp->tcpsocket为空,ns_interfacemgr_t类型的引用计数+1,也就是每创建一个ifp,mgr的引用计数就增加;ifp->mgr=ns_interfacemgr_t类型的mgr,同时会把该ifp添加到ns_interfacemgr_t类型的interfaces中
对于udp来说
它是dispatchmgr,因为它的端口要通过dispatch_t来管理
1.会根据给的的值设置ifp->mgr->dispatchmgr的信息;然后根据它的值创建一个dns_dispatch_t *disp,然后创建isc_socket_t *socket并且设置ns_g_socket的一些信息,比如fds,maxfd等,然后主进程bind,同时把socket信息赋值到disp上,并且注册disp事件,然后把disp赋值到ifp->mgr->dispatchmgr->list上
2.设置ifp->clientmgr,创建n个client,为每个client创建task,client的task也是设置到ns_g_taskmgr的,为每个client设置三个事件,为client设置message,设置recvbuf,最后把client添加到manager的active中
在执行完该函数以后,ifp->reference=client的个数,client->interface = ifp,ifp->udpdispatch->reference=client的个数,client->udpsocket=client->dispatch->sock=ifp->udpdispatch->sock
3.调用的函数:
dns_dispatch_getudp
ns_clientmgr_createclients
对于tcp来说
1.通过ifp->mgr->socketmgr创建socket,由前面可知这个数据依然是ns_g_socketmgr,因此后续同样对ns_g_socktmgr设置fd,maxfd等信息,然后主进程bind,listen.
2.设置ifp->clientmgr,所有的内容同udp一样,不同的在于,ifp->tcpsocket->reference=client的个数,client->tcplistener=ifp->tcpsocket(代表他有client个监听者)
load_configuration()
{
//加载配置文件之前,当发现对于ns_g_taskmgr有好几个running的task,那么则wait直到剩下一个为止
result = isc_task_beginexclusive(server->task);
//将acl的放到ns_g_dispatchmgr
if (server->blackholeacl != NULL)
dns_dispatchmgr_setblackhole(ns_g_dispatchmgr, server->blackholeacl);
//这些端口不能被监听
(void)ns_config_get(maps, "avoid-v4-udp-ports", &v4ports);
dns_dispatchmgr_setblackportlist(ns_g_dispatchmgr, portlist);
//开始获取监听的端口
ns_listenlist_t *listenon = NULL;
void)cfg_map_get(options, "listen-on", &clistenon);
//把监听的端口放到interfacemgr中进行管理
ns_interfacemgr_setlistenon4(server->interfacemgr,listenon);
//这个也是个重要的函数,上面确定了监听的端口,包括ipv4和ipv6的,下面开始进行处理
scan_interfaces(server, ISC_TRUE);
{
ns_interfacemgr_scan(server->interfacemgr, verbose);
{
ns_interfacemgr_scan0(mgr, NULL, verbose);
{
do_scan(mgr, ext_listen, verbose)
{
//处理ipv6的部分暂且不分析
//开始处理监听的端口
for (result = isc_interfaceiter_first(iter);result == ISC_R_SUCCESS;result = isc_interfaceiter_next(iter))
{
isc_interface_t interface;
result = isc_interfaceiter_current(iter, &interface);
ns_listenlist_t *ll = (family == AF_INET) ? mgr->listenon4 : mgr->listenon6;
ns_interface_t *ifp;
ns_interface_setup
{
ns_interface_t *ifp = NULL;
//下面这个赋值好ifp
result = ns_interface_create(mgr, addr, name, &ifp);
{
ifp = isc_mem_get(mgr->mctx, sizeof(*ifp));
//赋值
strncpy(ifp->name, name, sizeof(ifp->name));
result = ns_clientmgr_create(mgr->mctx, mgr->taskmgr,ns_g_timermgr,&ifp->clientmgr);
{
ns_clientmgr_t *manager;
manager->taskmgr = taskmgr;
manager->timermgr = timermgr;
manager->exiting = ISC_FALSE;
ISC_LIST_INIT(manager->active);
ISC_LIST_INIT(manager->inactive);
ISC_LIST_INIT(manager->recursing);
ifp->udpdispatch = NULL;
ifp->tcpsocket = NULL;
ifp->mgr = mgr
}
}
}
//创建udp的端口
result = ns_interface_listenudp(ifp);
{
result = dns_dispatch_getudp(ifp->mgr->dispatchmgr, ns_g_socketmgr, ns_g_taskmgr, &ifp->addr, 4096, 1000, 32768, 8219, 8237,attrs, attrmask, &ifp->udpdispatch);
{
result = dns_dispatchmgr_setudp(mgr, buffersize,maxbuffers,buckets, increment);
{
设置dns_dispatchmgr_t的一些内容
mgr->bpool;
mgr->maxbuffers = maxbuffers;
}
//查看是否已经有一个了,如果没有的话就创建
result = dispatch_find(mgr, localaddr, attributes, mask, &disp);
这里就是创建socket的代码了
result = dispatch_createudp(mgr, sockmgr, taskmgr,localaddr,maxrequests, attributes, &disp);
{
dns_dispatch_t *disp;
isc_socket_t *held[DNS_DISPATCH_HELD];
isc_socket_t *sock = NULL;
result = dispatch_allocate(mgr, maxrequests, &disp);
{
//从mgr->dpool申请空间
disp = isc_mempool_get(mgr->dpool);
赋值disp的一些属性
}
//创建isc_socket_t 类型的socket,初始化它的一些基本性质,并且调用socket
result = create_socket(sockmgr, localaddr, &sock);
{
result = isc_socket_create(mgr,isc_sockaddr_pf(local),isc_sockettype_udp, &sock);
{
sock = isc_mem_get(manager->mctx,sizeof(*sock));
sock->manager = manager;
sock->type = type;
sock->fd = -1;
//初始化socket的一些类型
ISC_LIST_INIT(sock->recv_list);
ISC_LIST_INIT(sock->send_list);
ISC_LIST_INIT(sock->accept_list);
//以及一些事件类型
ISC_EVENT_INIT(&sock->readable_ev, sizeof(intev_t),
}
switch (type) {
case isc_sockettype_udp:
sock->fd=socket(pf,SOCK_DGRAM,IPPROTO_UDP);
break;
}
下面是设置一些socket的属性
这里把socket设置到manger中,以便watcher线程可以开始监控它,但是注意这里还没有添加到manger的read_set中,所以select这个时候还不能检测到它
manager->fds[sock->fd] = sock;
manager->fdstate[sock->fd] = MANAGED;
ISC_LIST_APPEND(manager->socklist, sock, link);
if (manager->maxfd < sock->fd)
manager->maxfd = sock->fd;
//主线程开始监听该socket
result = isc_socket_bind(sock, local);
{
bind(sock->fd, &sockaddr->type.sa, sockaddr->length
}
}
//下面是设置disp的一些属性
disp->socktype = isc_sockettype_udp;
disp->socket = sock;
disp->local = *localaddr;
//创建一个task,指向ns_g_taskmgr,从他的mxtc申请内存
result = isc_task_create(taskmgr, 0, &disp->task);
disp->ctlevent = isc_event_allocate(mgr->mctx, disp,DNS_EVENT_DISPATCHCONTROL,destroy_disp, disp,sizeof(isc_event_t));
}
}//getudp
//创建cpu个clients,以上只是一个主进程在监听udp端口
result = ns_clientmgr_createclients(ifp->clientmgr,ns_g_cpus,ifp, ISC_FALSE);
{
for (i = 0; i < n; i++)
{
result = client_create(manager, &client);
{
client = isc_mem_get(mctx, sizeof(*client));
//让client->task=ns_g_taskmgr
result = isc_task_create(manager->taskmgr, 0, &client->task);
result = dns_message_create(client->mctx,DNS_MESSAGE_INTENTPARSE,&client->message);
{
dns_message_t *m = isc_mem_get(mctx, sizeof(dns_message_t));
//创建m的一些结构,
}
//创建client的三个最主要的事件
client->sendevent = (isc_socketevent_t *)isc_event_allocate(client->mctx, client,ISC_SOCKEVENT_SENDDONE,client_senddone, client,sizeof(isc_socketevent_t));
//设置recvbuf
client->recvbuf
//创建recevent
client->recvevent =isc_event_allocate(client_request)
//创建start事件,并且放到client->ctlevent中
ISC_EVENT_INIT(&client->ctlevent, sizeof(client->ctlevent), 0, NULL,NS_EVENT_CLIENTCONTROL, client_start,
//初始化query
result = ns_query_init(client);
}
//赋值上去,注意这里ifp的reference会++cp个数次
ns_interface_attach(ifp, &client->interface);
//如果是tcp的话
if(tcp)
{
ifp的tcpsocket引用计数会++,同时设置为client->tcplistenr
isc_socket_attach(ifp->tcpsocket,&client->tcplistener);
}
else//如果是udp的话
{
isc_socket_t *sock;
//ifp->udpdispatch的reference会++cpu个数次,client->dispatch会等于左边的
dns_dispatch_attach(ifp->udpdispatch,&client->dispatch);
//下面的这俩个操作就是client->udpsocket会赋值左边的,client->dispatch的引用计数会++
sock = dns_dispatch_getsocket(client->dispatch);
isc_socket_attach(sock, &client->udpsocket);
}
//每个client添加到active中,并且通过list可以找到下一个
ISC_LIST_APPEND(manager->active, client, link);
client->list = &manager->active;
//取出client_start事件,交给工作线程去执行client_start
ev = &client->ctlevent;
isc_task_send(client->task, &ev);
}
}
}//listenudp
//这是tcp的
result = ns_interface_accepttcp(ifp);
{
//创建一个tcpsocket,注意ifp->mgr->socketmgr也是ns_g_socketmgr
result = isc_socket_create(ifp->mgr->socketmgr,isc_sockaddr_pf(&ifp->addr),isc_sockettype_tcp,&ifp->tcpsocket);
{
//同上创建socket,并且把该fd赋值manger的一些信息
}
//调用bind
result = isc_socket_bind(ifp->tcpsocket, &ifp->addr);
//调用listen
result = isc_socket_listen(ifp->tcpsocket, ns_g_listen);
{
listen(sock->fd)
}
//注意以上都是主进程在监听端口
ns_clientmgr_createclients(ifp->clientmgr,ifp->ntcptarget, ifp,ISC_TRUE);
{
同udp一样创建n个client以及赋值事件
}
}//listentcp
}
}
}
}
}
//注意在扫描完监听的端口以后,这里还有一个比较重要的函数,就是和view相关的函数
views = NULL;
//获取到view的配置项
(void)cfg_map_get(config, "view", &views);
//可能会配置多个view
for (element = cfg_list_first(views);element != NULL;element = cfg_list_next(element))
{
//下面先创建view,然后配置
const cfg_obj_t *vconfig = cfg_listelt_value(element);
create_view(vconfig, &viewlist, &view)
//注意如果要使用dlz的话则需要在配置文件中进行相关配置
configure_view(view, config, vconfig,ns_g_mctx, &aclconfctx, ISC_TRUE)
{
#ifdef DLZ
//赋值配置项dlz
cfg_map_get(voptions, "dlz", &dlz);
if (dlz != NULL)
{
obj = cfg_tuple_get(dlz, "name");
result = dns_dlzcreate(mctx, cfg_obj_asstring(obj),dlzargv[0], dlzargc, dlzargv,&view->dlzdatabase);
{
//注意这里的dlzname就是dlz后面配置的内容,drivername则是空格前面的内容
//那个通用的接口,它的method是通用的方法
dns_dlzimplementation_t *impinfo;
//在dlz_implementations list中找到该驱动对应的结构,这个是在driver_init的时候已经做好了
impinfo = dlz_impfind(drivername);
//声明一个dns_dlzdb_t的结构
(*dbp) = isc_mem_get(mctx, sizeof(dns_dlzdb_t));
//赋值该db的implementation结构
(*dbp)->implementation = impinfo;
//使用create创造db,注意这个create就是所有的dlz公有的方法dns_sdlzcreate
result = ((impinfo->methods->create)(mctx, dlzname, argc, argv,impinfo->driverarg, &(*dbp)->dbdata));
{
//这个结构的method就是每个dlz自己私有的数据了
dns_sdlzimplementation_t *imp;
//取到dlz带有自己的属性的那个结构
imp = driverarg;
//注意这里的这个方法就是dlz自己特有的方法,也就是F_dns_create方法
result = imp->methods->create(dlzname, argc, argv,imp->driverarg, dbdata);
{
}
}
}
}
}
}
}
//下面是对load_zones的分析,该函数其实是数据资源
load_zones()
{
//同样加载区文件的时候工作线程也是停止工作的
result = isc_task_beginexclusive(server->task);
for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; view = ISC_LIST_NEXT(view, link))
{
CHECK(dns_view_load(view, stop));
{
return (dns_zt_load(view->zonetable, stop));
{
result = dns_zt_apply(zt, stop, load, NULL);
{
return (dns_zt_apply2(zt, stop, NULL, action, uap));
{
dns_rbtnode_t *node;
dns_rbtnodechain_t chain;
//申请chain空间
dns_rbtnodechain_init(&chain, zt->mctx);
zt->table转向chain链
result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL);
while()
{
//开始加载zone区
result = (action)(zone, uap);
}
}
//这里重点分析一下load函数
load
{
result = dns_zone_load(zone);
return (zone_load(zone, 0));
{
//这个就是前面创建十三个根服务器的那个函数,这里相当于创建zone文件,创建一个rbt类型的db,给他赋予了zone_method,同时把它赋值给db
result = dns_db_create(zone->mctx, zone->db_argv[0],&zone->origin, (zone->type == dns_zone_stub) ?dns_dbtype_stub : dns_dbtype_zone,1,zone->rdclass, zone->db_argc - 1, zone->db_argv +1,&db);
//调用db的method
dns_db_settask(db, zone->task);
//这里就创建了db,同时使用db的一些方法对zone文件进行加载
result = zone_startload(db, zone, loadtime);
{
dns_load_t *load=isc_mem_get(zone->mctx, sizeof(*load))
}
}
}
}
}
}
}
}
在此之前只有一个线程在监听端口,当发送完事件以后,多个client同时开始执行client_start
对于要发给工作线程的事件,它的事件的ev_sender装的是socket,对于要发给watcher线程去监听的事件,它的ev_sender装的是task
一定要注意在client_start中才让watcher线程开始监听该端口
对于udp来说,在通讯的时候不需要建立连接,到达的数据就直接是请求,因此client_start做的就是在内部调用doio_recv函数,如果这个时候没有查询请求的话,那就把该事件放到sock->recv_list中,同时把该socket放到watcher线程中监听,如果有请求的话,那就从事件的ev_sender中取出task,然后把它换成sock,然后发送给工作线程去处理,然后工作线程就可以处理eventrecv事件了
对于tcp来说,他还是一个监听端口,因此需要交给watcher线程去监听
client_start
{
if(udp)
{
client_udprecv(client)
{
isc_region_t r;
r.base = client->recvbuf;
r.length = RECV_BUFFER_SIZE;
//对于udp来说,线程已经开始监听端口了,那么当有数据来的时候应该去读数据,所以这里开始转换client的recevent作为下次数据来时候的action
result = isc_socket_recv2(client->udpsocket, &r, 1,client->task, client->recvevent, 0);
{
//设置事件对应的端口
event->ev_sender = sock;
ISC_LIST_INIT(event->bufferlist);
event->region = *region;
if (sock->type == isc_sockettype_udp)
{
event->minimum = 1;
}
else
{
if (minimum == 0)
event->minimum = region->length;
else
event->minimum = minimum;
}
return (socket_recv(sock, event, task, flags));
{
dev->ev_sender = task;
//如果是udp的话,则直接调用recvmsg
if (sock->type == isc_sockettype_udp) {
io_state = doio_recv(sock, dev);
} else {
LOCK(&sock->lock);
have_lock = ISC_TRUE;
if (ISC_LIST_EMPTY(sock->recv_list))
io_state = doio_recv(sock, dev);
else
io_state = DOIO_SOFT;
}
switch (io_state)
{
//这个时候该端口并没有请求过来,因此排队处理
case DOIO_SOFT:
task->referencr++;
ntask = task
//这里把该端口加入到watcher线程中
if (ISC_LIST_EMPTY(sock->recv_list))
select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
//把该事件放入到recv_list中
ISC_LIST_ENQUEUE(sock->recv_list, dev, ev_link);
break
case DOIO_HARD:
case DOIO_SUCCESS:
//返回他意味着有消息来了,那么立刻让工作线程去处理,在发送之前会从事件的ev_sender中取出task,会赋值该字段为sock,这样的话工作线程在处理的时候就知道该往那个sock发送数据了
if ((flags & ISC_SOCKFLAG_IMMEDIATE) == 0)
send_recvdone_event(sock, &dev);
{
//这下可以很好的理解了,因为这件事情已经处理完了,因此从recv_list中移除该事件
}
break;
}
}
}
}
}
//这是tcp的情况,对于tcp来说接下来应该调用accept了,他要比udp多一道程序,它首先要建立连接拿到新的fd
else
{
client_accept(client);
{
//new_conn就是连接请求过来以后调用的程序,就是建立好连接
result = isc_socket_accept(client->tcplistener, client->task,client_newconn, client);
{
isc_socketmgr_t *manager = sock->manager
//这里在初始化一个事件,就是建立连接的事件
isc_socket_newconnev_t *dev = (isc_socket_newconnev_t *)isc_event_allocate(manager->mctx, task, ISC_SOCKEVENT_NEWCONN,action, arg, sizeof(*dev));
//声明一个新的isc_socket_t的结构,因为accept以后拿到的就是新的socket
result = allocate_socket(manager, sock->type, &nsock);
//发送事件之前要把他的ev_sender换成task,因为它这个时候还是需要监听该socket,所以要把这件事情交给watcher线程来做,
dev->ev_sender = ntask;
dev->newsocket = nsock;
//下面就是把该socket放到watcher线程中去监听,也就是他现在是一个listen的状态
if (ISC_LIST_EMPTY(sock->accept_list))
do_poke = ISC_TRUE;
ISC_LIST_ENQUEUE(sock->accept_list, dev, ev_link);
if (do_poke)
select_poke(manager, sock->fd, SELECT_POKE_ACCEPT);
}
}
}
}