test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "hash.h"
//编写hash函数
unsigned int hash_func(unsigned int bucktes, ip_port_t *ipp)
{
uint32_t key = (ipp->saddr ^ ipp->daddr ^ ipp->dport) % bucktes;
printf("get buckets saddr:%x daddr:%x dport:%x --> key:%u\n", ipp->saddr, ipp->daddr, ipp->dport, key);
ipp->key = key;
return 1;
}
int main(int argc, char *argv[])
{
ip_port_t ipp_arry[] = {
{0, 0x7509A8C0, 0x710CA8C0, 0x59, 0 },
{0, 0x7509A8C1, 0x710CA8C2, 0x58, 0 },
{0, 0x7509A8C2, 0x710CA8C3, 0x57, 0 },
{0, 0x7509A8C3, 0x710CA8C4, 0x56, 0 },
{0, 0x7509A8C4, 0x710CA8C5, 0x55, 0 },
{0, 0x7509A8C5, 0x710CA8C6, 0x54, 0 },
{0, 0x7509A8C6, 0x710CA8C7, 0x53, 0 },
{0, 0x7509A8C7, 0x710CA8C8, 0x52, 0 },
{0, 0x7509A8C8, 0x710CA8C9, 0x51, 0 }
};
hash_t *hash = hash_init(MAX_BUCKETS_SIZE);
int i = 0;
int size = sizeof(ipp_arry) / sizeof(ipp_arry[0]);
for (i = 0; i < size - 4; i++)
{
hash_func(MAX_BUCKETS_SIZE, &ipp_arry[i]);
hash_add_entry(hash, &ipp_arry[i]);
}
printf("......................add end...............\n");
hash_node_t *hn = NULL;
for (i = 0; i < size - 4; i++)
{
hn = (hash_node_t *)hash_lookup_entry(hash, &ipp_arry[i]);
if (hn) {
printf("find [%d]:%x,%x,%x,%x\n", i, hn->saddr, hn->daddr, hn->dport, hn->timeout);
}
else {
printf("[%d]:no node \n", i);
}
}
for (i = 0; i < size; i++)
{
hash_del_entry(hash, &ipp_arry[i]);
}
printf("......................free end...............\n");
for (i = 0; i < size; i++)
{
hn = (hash_node_t *)hash_lookup_entry(hash, &ipp_arry[i]);
if (hn) {
printf("after free find [%d]:%x,%x,%x,%x\n", i, hn->saddr, hn->daddr, hn->dport, hn->timeout);
}
else {
printf("after free [%d]:no node \n", i);
}
}
for (i = 0; i < size ; i++)
{
hash_func(MAX_BUCKETS_SIZE, &ipp_arry[i]);
ipp_arry[i].timeout = time(NULL);
printf("add entry [%d] timeout:%lu\n", i, ipp_arry[i].timeout);
hash_add_entry(hash, &ipp_arry[i]);
sleep(1);
}
printf("......................add end 2...............\n");
hn = NULL;
for (i = 0; i < size; i++)
{
hn = (hash_node_t *)hash_lookup_entry(hash, &ipp_arry[i]);
if (hn) {
printf("find 2 [%d]:%x,%x,%x,%lu\n", i, hn->saddr, hn->daddr, hn->dport, hn->timeout);
}
else {
printf("[%d]:no node \n", i);
}
}
ip_port_t ipp;
while(hash->timeout_nodes)
{
time_t tm_now = time(NULL);
if(tm_now - hash->timeout_nodes->timeout > 5) {
printf("goto delete timeout now:%lu - %lu\n", tm_now, hash->timeout_nodes->timeout);
ipp.saddr = hash->timeout_nodes->saddr;
ipp.daddr = hash->timeout_nodes->daddr;
ipp.dport = hash->timeout_nodes->dport;
hash_func(MAX_BUCKETS_SIZE, &ipp);
hash_del_entry(hash, &ipp);
}
sleep(1);
}
printf("......................delete timeout end...............\n");
for (i = 0; i < size; i++)
{
hn = (hash_node_t *)hash_lookup_entry(hash, &ipp_arry[i]);
if (hn) {
printf("find 3 [%d]:%x,%x,%x,%lu\n", i, hn->saddr, hn->daddr, hn->dport, hn->timeout);
}
else {
printf("[%d]:no node \n", i);
}
}
return 0;
}
hash.h
#pragma once
#ifndef _HASH_H_
#define _HASH_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <time.h>
#define MAX_BUCKETS_SIZE 1024
typedef struct ip_port {
uint32_t key;//
uint32_t saddr;//
uint32_t daddr;//
uint16_t dport;//
time_t timeout;//
}ip_port_t;
typedef struct hash_node {
uint32_t saddr;//
uint32_t daddr;//
uint16_t dport;//
time_t timeout;//
struct hash_node *prev;
struct hash_node *next;
struct hash_node *timeout_prev;
struct hash_node *timeout_next;
}hash_node_t;
typedef struct hash {
unsigned int buckets;//桶的个数(大小)
hash_node_t **nodes;//hash表中存放的链表地址
hash_node_t * free_nodes;
hash_node_t * timeout_nodes;
hash_node_t * timeout_tail;
}hash_t;
/*返回的是hash表指针,创建hash表*/
hash_t *hash_init(unsigned int);
void *hash_lookup_entry(hash_t *, ip_port_t *);
void hash_add_entry(hash_t *, ip_port_t *);
void hash_del_entry(hash_t *, ip_port_t *);
#endif /*_HASH_H_*/
hash.c
#include "hash.h"
hash_node_t * hash_get_free_nodes(hash_t *hash);
void hash_add_free_nodes(hash_t *hash, hash_node_t *node);
void hash_add_timeout_nodes(hash_t *hash, hash_node_t *node);
void hash_del_timeout_nodes(hash_t *hash, hash_node_t *node);
hash_t *hash_init(unsigned int buckets)
{
hash_t *hash = (hash_t *)malloc(sizeof(hash_t));
memset(hash, 0x00, sizeof(hash_t));
hash->buckets = buckets;
unsigned int size = buckets * sizeof(hash_node_t *);
hash->nodes = (hash_node_t **)malloc(size);
memset(hash->nodes,0x00, size);
return hash;
}
void* hash_lookup_entry(hash_t *hash, ip_port_t *ipp)
{
hash_node_t *node = hash->nodes[ipp->key];
if (node == NULL) return NULL;
while (node != NULL ) {
if (node->saddr == ipp->saddr && node->daddr == ipp->daddr && node->dport == ipp->dport)
return node;
node = node->next;
}
return NULL;
}
void hash_add_entry(hash_t *hash, ip_port_t *ipp)
{
if (hash_lookup_entry(hash, ipp)) {
printf("duplicate hash key\n");
return;
}
hash_node_t *node;
node = hash_get_free_nodes(hash);
if (node == NULL) {
node = (hash_node_t*)malloc(sizeof(hash_node_t));
if (node == NULL) {
printf("error: add entry malloc node!\n");
exit(-1);
}
printf("add entry malloc node=========================\n");
}
else {
printf("add entry get free node=========================\n");
}
node->next = NULL;
node->prev = NULL;
node->timeout_next = NULL;
node->timeout_prev = NULL;
node->saddr = ipp->saddr;
node->daddr = ipp->daddr;
node->dport = ipp->dport;
node->timeout = ipp->timeout;
hash_node_t **bucket = &(hash->nodes[ipp->key]);
if (*bucket == NULL) {
*bucket = node;
}
else {
node->next = *bucket; //first is next
(*bucket)->prev = node;
*bucket = node;
}
//add to timeout nodes
hash_add_timeout_nodes(hash, node);
}
void hash_del_entry(hash_t *hash, ip_port_t *ipp)
{
hash_node_t *node = hash_lookup_entry(hash, ipp);
if (node == NULL)
return;
if (node->prev) {
node->prev->next = node->next;
}
else {
hash_node_t **bucket = &(hash->nodes[ipp->key]);
*bucket = node->next;
}
if (node->next) {
node->next->prev = node->prev;
}
//del from timeout nodes
hash_del_timeout_nodes(hash, node);
//add to free nodes
hash_add_free_nodes(hash, node);
}
void hash_add_free_nodes(hash_t *hash, hash_node_t *node)
{
node->next = NULL;
node->prev = NULL;
if (hash->free_nodes == NULL) {
hash->free_nodes = node;
}
else {
node->next = hash->free_nodes; //first is next
hash->free_nodes->prev = node;
hash->free_nodes = node;
}
}
hash_node_t * hash_get_free_nodes(hash_t *hash)
{
hash_node_t *node = hash->free_nodes;
if (node == NULL)
return NULL;
if (node->next) {
node->next->prev = NULL;
}
hash->free_nodes = node->next;
node->next = NULL;
return node;
}
void hash_add_timeout_nodes(hash_t *hash, hash_node_t *node)
{
if (hash->timeout_nodes == NULL) {
hash->timeout_nodes = hash->timeout_tail = node;
}
else {
hash->timeout_tail->timeout_next = node;
node->timeout_prev = hash->timeout_tail;
hash->timeout_tail = node;
}
}
void hash_del_timeout_nodes(hash_t *hash, hash_node_t *node)
{
if (node->timeout_prev) {
node->timeout_prev->timeout_next = node->timeout_next;
}
else {
hash->timeout_nodes = node->timeout_next;
}
if (node->timeout_next) {
node->timeout_next->timeout_prev = node->timeout_prev;
}
else {
hash->timeout_tail = node->timeout_prev;
}
}