利用链表实现:
假如学校的DNS镜像服务器内存里有2亿条左右域名记录,每条域名信息里记录了3个东西“域名、IP地址、资源(比如www、ftp之类)”,该镜像服务器每天根据权威域名服务器下发的变动表(假如以文件形式下发)做一次更新。现在我们要来做这个事情,实现这个DNS镜像服务器核心算法的设计,做到高效的域名解析和域名数据更新。
为了实现高效的域名解析和更新操作,可以使用哈希表和链表结合的方式存储域名信息。
具体实现如下:
1.定义一个域名信息结构体DNSnode,包括域名、IP地址、资源。
typedef struct DNSnode{
char domain[256];
char ip[16];
char resource[32];
struct DNSnode *next;
}DNSnode;
2.使用哈希表存储每个域名信息的指针。为了减少哈希冲突,可以采用链地址法解决冲突。定义一个DNS缓存结构体DNSCache,包括哈希表大小、哈希表数组指针、每个哈希槽的链表头指针。
#define HASH_SIZE 100000
typedef struct DNSCache{
int size;
DNSnode **hashtable;
DNSnode *head[HASH_SIZE];
}DNSCache;
其中,size表示哈希表大小,hashtable表示哈希表数组指针,head数组表示每个哈希槽的链表头指针。
3.实现哈希函数,根据域名将其映射到哈希表中的一个槽中。
int hash(char *domain){
int hash = 0;
int len = strlen(domain);
for(int i = 0; i < len; i++){
hash = (hash << 5) + hash + domain[i];
}
return hash % HASH_SIZE;
}
实现插入、查找、删除操作。
插入操作:
void insertDNS(DNSCache *cache, char *domain, char *ip, char *resource){
int key = hash(domain);
DNSnode *temp = cache->head[key];
while(temp != NULL){
if(strcmp(temp->domain, domain) == 0){
strcpy(temp->ip, ip);
strcpy(temp->resource, resource);
return;
}
temp = temp->next;
}
DNSnode *new_node = (DNSnode*)malloc(sizeof(DNSnode));
strcpy(new_node->domain, domain);
strcpy(new_node->ip, ip);
strcpy(new_node->resource, resource);
new_node->next = cache->head[key];
cache->head[key] = new_node;
cache->size++;
}
查找:
DNSnode *findDNS(DNSCache *cache, char *domain){
int key = hash(domain);
DNSnode *temp = cache->head[key];
while(temp != NULL){
if(strcmp(temp->domain, domain) == 0){
return temp;
}
temp = temp->next;
}
return NULL;
}
删除操作:
void deleteDNS(DNSCache *cache, char *domain){
int key = hash(domain);
DNSnode *temp = cache->head[key];
DNSnode *prev = NULL;
while(temp != NULL){
if(strcmp(temp->domain, domain) == 0){
if(prev == NULL){
cache->head[key] = temp->next;
}else{
prev->next = temp->next;
}
free(temp);
cache->size--;
return;
}
prev = temp;
temp = temp->next;
}
}
5.实现域名解析和更新操作。
域名解析操作,根据传入的域名在哈希表中查找对应的域名信息,如果找到则返回IP地址,否则返回NULL。
char *resolveDNS(DNSCache *cache, char *domain){
DNSnode *node = findDNS(cache, domain);
if(node == NULL){
return NULL;
}else{
return node->ip;
}
}
域名更新操作,根据传入的变动表文件名,解析其中每一条域名记录,对于已有的域名进行更新操作,对于新增的域名进行插入操作,对于已被删除的域名进行删除操作。
void updateDNS(DNSCache *cache, char *filename){
FILE *fp = fopen(filename, "r");
if(fp == NULL){
printf("Error: file not found!\n");
return;
}
char line[512];
while(fgets(line, 512, fp) != NULL){
char domain[256];
char ip[16];
char resource[32];
int index = 0;
int i = 0;
while(line[index] != ' '){
domain[i++] = line[index++];
}
domain[i] = '\0';
index++;
i = 0;
while(line[index] != ' '){
ip[i++] = line[index++];
}
ip[i] = '\0';
index++;
i = 0;
while(line[index] != '\n'){
resource[i++] = line[index++];
}
resource[i] = '\0';
DNSnode *node = findDNS(cache, domain);
if(node == NULL){
// insert new node
insertDNS(cache, domain, ip, resource);
}else{
// update existing node
strcpy(node->ip, ip);
strcpy(node->resource, resource);
}
}
fclose(fp);
// delete non-existing nodes
for(int i = 0; i < HASH_SIZE; i++){
DNSnode *temp = cache->head[i];
while(temp != NULL){
char *ip = resolveDNS(cache, temp->domain);
if(ip == NULL){
deleteDNS(cache, temp->domain);
}
temp = temp->next;
}
}
}