双链表示例

1. 简介

本双链表的实现主要参考了kernel中的双链表。

实现由3个文件组成:

  • db_list.h 双链表定义及相关的API
  • db_list.c 双链表的实现
  • test1.c 测试程序

2. db_list.h

/**
 * db_list.h : public header for application
 */

#ifndef DB_LIST_H
#define DB_LIST_H

#include <stdint.h>

/**
 * Basic structures
 */
typedef void info_t;

typedef struct node {
	info_t *info;
	struct node *next;
	struct node *prev;
} node_t;

typedef struct list {
	node_t *head;
	node_t *tail;
	node_t *current;
	size_t info_size;
	unsigned long current_index;
	unsigned long list_size;
} list_t;

/**
 * Prototypes
 */
/* List initialization routines */
list_t *list_create(list_t ** list);
int list_init(list_t * list, size_t info_size);
void list_destroy(list_t ** list);

/* Status and state routines */
int list_empty(list_t * list);
unsigned long get_list_size(list_t * list);

/* List update routines */
int list_add(list_t * list, info_t * info);
int list_add_tail(list_t * list, info_t * info);
int list_replace(list_t * list, node_t * new_node);
int list_del(list_t * list);
int list_clear(list_t * list);
int list_move(list_t * list, list_t * list_a);
int list_move_tail(list_t * list, list_t * list_a);

/* List search routines */
int find_record(list_t * list, info_t * match, int (*cmp) (info_t *, info_t *));
info_t *get_current_record(list_t * list);
info_t *get_next_record(list_t * list);
info_t *get_prev_record(list_t * list);
info_t *get_first_record(list_t * list);
info_t *get_last_record(list_t * list);

/* Input/Output routines */
int export_list(list_t * list, const char *path);
int import_list(list_t * list, const char *path);

#endif /* DB_LIST_H */

2. db_list.c

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <strings.h>
#include "db_list.h"

/**
 * create a struct of type list_t
 */
list_t *list_create(list_t ** list)
{
	if ((*list = (list_t *) malloc(sizeof(list_t))) == NULL)
		return (NULL);
	return *list;
}

/**
 * initialize double linked list.
 */
int list_init(list_t * list, size_t info_size)
{
	if (info_size == (size_t) 0) {
		perror("info size should not be zero!\n");
		return -1;
	}
	if (list == NULL) {
		perror("list it null\n");
		return -1;
	}
	list->head = NULL;
	list->tail = NULL;
	list->current = NULL;
	list->info_size = info_size;
	list->list_size = 0L;
	list->current_index = 0L;
	return 0;
}

/**
 * destroy_list - destroy the list and all of its members
 */
void list_destroy(list_t ** list)
{
	if (*list == NULL) {
		perror("list it null\n");
		return;
	}
	list_clear(*list);
	free(*list);
	*list = NULL;
}

/**
 * tests whether the list is empty
 */
int list_empty(list_t * list)
{
	if ((list->head == NULL) || (list->tail == NULL))
		return 0;
	return -1;
}

unsigned long get_list_size(list_t * list)
{
	if (list_empty(list) == 0)
		return 0;
	return list->list_size;
}

int list_add(list_t * list, info_t * info)
{
	node_t *new_node;

	if ((new_node = (node_t *) malloc(sizeof(node_t))) == NULL)
		return -1;
	/* first node */
	if (list->head == NULL) {
		new_node->info = info;
		new_node->prev = NULL;
		new_node->next = NULL;
		list->head = new_node;
		list->tail = new_node;
		list->current = new_node;
		list->current_index = 1L;
		list->list_size = 1L;
		return 0;
	}
	new_node->info = info;
	new_node->prev = list->current;
	new_node->next = list->current->next;
	if (list->current->next != NULL)
		list->current->next->prev = new_node;
	else
		list->tail = new_node;
	list->current->next = new_node;
	list->current = new_node;
	list->current_index++;
	list->list_size++;

	return 0;
}

int list_add_tail(list_t * list, info_t * info)
{
	node_t *new_node;
	if ((new_node = (node_t *) malloc(sizeof(node_t))) == NULL)
		return -1;
	if (list->head == NULL) {
		new_node->info = info;
		new_node->prev = NULL;
		new_node->next = NULL;
		list->head = new_node;
		list->tail = new_node;
		list->current = new_node;
		list->current_index = 1L;
		list->list_size = 1;
		return 0;
	}
	new_node->info = info;
	new_node->next = NULL;
	new_node->prev = list->current;
	list->current->next = new_node;
	list->current = new_node;
	list->tail = new_node;
	list->current_index++;
	list->list_size++;

	return 0;
}

int record_update(list_t * list, info_t * record)
{
	return 0;
	list_del(list);
	list_add(list, record);
}

int list_del(list_t * list)
{
	node_t *old_node;
	info_t *old_info;
	if (list->current == NULL)
		return -1;
	old_node = list->current;
	old_info = list->current->info;

	if (list->current == list->head) {	/* current is first record */
		if (list->current->next != NULL)
			list->current->next->prev = NULL;
		list->head = list->current->next;
		list->current = list->head;
	} else if (list->current == list->tail) {	/* current is last record */
		list->current->prev->next = NULL;
		list->tail = list->current->prev;
		list->current = list->tail;
		list->current_index--;
	} else {		/* current is a middle record */
		list->current->prev->next = list->current->next;
		list->current->next->prev = list->current->prev;
		list->current = list->current->next;
	}
	free(old_info);
	free(old_node);
	list->list_size--;
	return 0;
}

int list_clear(list_t * list)
{
	node_t *old_node;
	info_t *old_info;
	if (list->head == NULL)
		return -1;
	while (list->head) {
		old_node = list->head;
		old_info = list->head->info;
		list->head = list->head->next;
		free(old_info);
		free(old_node);
	}
	return 0;
}

int find_record(list_t * list, info_t * match, int (*cmp) (info_t *, info_t *))
{
	if (list->head == NULL || cmp == NULL)
		return -1;
	list_t *tmplist;

	tmplist=list_create(&tmplist);

	list->current = list->head;
	list->current_index = 1;

	/* save current state */
	tmplist->head = list->head;
	tmplist->current = list->current;
	tmplist->current_index=list->current_index;
	tmplist->tail = list->tail;
	while (list->current) {
		if ((cmp(list->current->info, match)) != 0) {
			list->current = list->current->next;
			list->current_index++;
		}else {
			list->current = tmplist->current;
			list->current_index = list->current_index;
			free(tmplist);
			return 0;
		}
	}

	list->current = tmplist->current;
	list->current_index = list->current_index;
	free(tmplist);
	return -1;
}

info_t *get_current_record(list_t * list)
{
	return (list->current == NULL) ? NULL : list->current->info;
}

info_t *get_next_record(list_t * list)
{
	return (list->current->next == NULL) ? NULL : list->current->next->info;
}

info_t *get_prev_record(list_t * list)
{
	return (list->current->prev == NULL) ? NULL : list->current->prev->info;
}

info_t *get_first_record(list_t * list)
{
	return (list->head == NULL) ? NULL : list->head->info;
}

info_t *get_last_record(list_t * list)
{
	return (list->tail == NULL) ? NULL : list->tail->info;
}

/* export list to file */
int export_list(list_t * list, const char *path)
{
	node_t *p;
	FILE *fp;

	if ((fp = fopen(path, "wb+")) == NULL) {
		perror("fopen error!\n");
		return -1;
	}
	p = list->head;
	while (p) {
		if ((fwrite(p->info, list->info_size, 1, fp)) !=
		    list->info_size) {
			printf("fwrite error!\n");
			fclose(fp);
			return -1;
		}
		p = p->next;
	}
	fclose(fp);

	return 0;
}

/* import list from file */
int import_list(list_t * list, const char *path)
{
	info_t *info;
	FILE *fp;

	list_clear(list);
	if ((fp = fopen(path, "rb")) == NULL)
		return -1;
	if ((info = (info_t *) malloc(list->info_size)) == NULL)
		return -1;
	while (feof(fp)) {
		if (fread(info, list->info_size, 1, fp) != list->info_size)
			return -1;
		if (list_add_tail(list, info) == -1)
			return -1;
	}

	free(info);
	fclose(fp);
	return 0;
}

3. test1.c

测试程序实现了一个简单的基于双链表的流表,支持简单的增删改查。
在网络处理中,通常将一个会话称为一个流。流由五元组(sip,dip,sport,dport,ip protocol)组成。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <sys/types.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <unistd.h>
#include <stdint.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "db_list.h"

typedef struct stream {
	uint32_t sip;
	uint32_t dip;
	uint16_t sport;
	uint16_t dport;
	unsigned char  proto;
}stream_t;
int cmp(void *src, void *dst);
int check_stream(stream_t * s, list_t * list);
void get_prev_stream(list_t * list);
void get_current_stream(list_t * list);
void get_next_stream(list_t * list);
void get_first_stream(list_t * list);
void get_last_stream(list_t * list);
void get_all_stream(list_t * list);
void show_usage();
void show_version();
void process_cmd_add(char **cmd); 
void process_cmd_check(char **cmd); 
void process_cmd_show(char **cmd,int token_cnt); 
void process_cmd_del(char **cmd,int token_cnt); 
void process_cmd_size(); 
void process_cmd_import(char **cmd); 
void process_cmd_export(char **cmd); 
void process_cmd_clear();
int get_stream_size(list_t * list);
static int parse_cmd_line(char *cl, char **argv, int max_argv);
int get_token_count(char *buffer, char delimit, int *count);
char *stripwhite(char *string);
void sig_int(int a);

list_t *g_slist = NULL;
char *cmd[7]; /* store command tokens */
int main(int argc, char **argv)
{
	int i;
	int token_cnt;
	char *string = NULL;
	char *s;
//char *cmd[7]; /* store command tokens */
	
	if ((g_slist = list_create(&g_slist)) == NULL) {
		perror("list create error!\n");
		exit(1);
	}
	if (list_init(g_slist, sizeof(stream_t)) != 0) {
		perror("list init error!\n");
		exit(1);
	}
	if (argc==2 && strncmp(argv[1], "test", sizeof("test"))==0) {
		uint32_t sip, dip;
		uint16_t sport, dport;
		char buf[80], *tmp;
		for(;;){
			for (i=0; i<10; i++) {
				signal(SIGINT, sig_int);
				time_t t;
				srand((unsigned)time(&t));
				sip = rand()%400000000;
				dip = rand()%400000000;
				sport = rand()% 65535;
				dport = rand()% 65535;
				memset(buf, '\0', sizeof(buf));
				sprintf(buf, "add %d %d %d %d tcp", sip, dip, sport, dport);
			//	printf("buf = %s\n", buf);
				//char *cmd[6];
				tmp = buf;
				if (get_token_count(buf, ' ', &token_cnt)!=0) 
					return (-1);
				for (i = 0; i < token_cnt ; i++)
					cmd[i] = (char *)malloc(18*sizeof(char));
				parse_cmd_line(tmp, cmd, token_cnt);
				process_cmd_add(cmd);
				for (i=0;i<token_cnt;i++)
					free(cmd[i]);
				usleep(100);
			}
			sleep(1);
			list_destroy(&g_slist);
			return 0;
		}
	}

	/* process command options */
	for (;;) {
		string = readline("CLI>");
		s=stripwhite(string);
		if (strlen(s) == 0) {
			continue;
		}
		/* if the command is null */
		if (get_token_count(string, ' ', &token_cnt) != 0) {
			free(s);
			continue;
		}
		for (i = 0; i < token_cnt; i++) {
			cmd[i] = (char *)malloc(18 * sizeof(char));
		}
		parse_cmd_line(s, cmd, token_cnt);

		if ((memcmp("add", cmd[0], sizeof("add")) == 0)&&
				token_cnt == 6)
			process_cmd_add(cmd);
		else if ((memcmp("del", cmd[0], sizeof("del")) == 0) &&
				((token_cnt == 1)||(token_cnt == 6)))
			process_cmd_del(cmd, token_cnt);
		else if ((memcmp("check", cmd[0], sizeof("check")) == 0) &&
				token_cnt == 6)
			process_cmd_check(cmd);
		else if ((memcmp("show", cmd[0], sizeof("show")) == 0) &&
				(token_cnt == 1 || token_cnt==2))
			process_cmd_show(cmd, token_cnt);
		else if ((memcmp("size", cmd[0], sizeof("size")) == 0) &&
				token_cnt == 1)
			process_cmd_size();
		else if ((memcmp("help", cmd[0], sizeof("help")) == 0) &&
				token_cnt == 1)
			show_usage();
		else if ((memcmp("version", cmd[0], sizeof("version")) == 0) &&
				token_cnt == 1)
			show_version();
		else if ((memcmp("exit", cmd[0], sizeof("exit")) == 0) &&
				token_cnt == 1)
			goto end;
		else if ((memcmp("import", cmd[0], sizeof("import")) == 0) &&
				token_cnt == 2)
			process_cmd_import(cmd);
		else if ((memcmp("export", cmd[0], sizeof("export")) == 0) &&
				token_cnt == 2)
			process_cmd_export(cmd);
		else if ((memcmp("clear", cmd[0], sizeof("clear")) == 0) &&
				token_cnt == 1)
			process_cmd_clear();	//clear all nodes.

		for (i = 0; i < token_cnt; i++) {
			char *tmp = cmd[i];
			free(tmp);
		}
		free(s);
	}
end:
	list_destroy(&g_slist);
	for (i = 0; i < token_cnt; i++) {
		char *tmp = cmd[i];
		free(tmp);
	}
	free(s);
	return 0;
}

/**
 * cmp two stream
 * 0 means equal.
 */
int cmp(void *src, void *dst)
{
	
	stream_t *s, *d;
	s = (stream_t *) src;
	d = (stream_t *) dst;
	if ((s->sip == d->sip) &&
		(s->dip == d->dip) &&
		(s->sport == d->sport) &&
		(s->dport == d->dport) &&
		(s->proto == d->proto))
		return 0;
	return -1;
}

void process_cmd_size()
{
	unsigned long int i;
	i = get_list_size(g_slist);
	if (i == 0) {
		printf("empty stream list\n");
		return;
	}
	printf("stream counter:\t%ld\n", i);
}
void process_cmd_add(char **cmd)
{
	stream_t *s;
	struct in_addr saddr, daddr;
	if ((s = (stream_t *) malloc(sizeof(stream_t))) == NULL) {
		perror("malloc error in process_cmd_add\n");
		return;
	}
	if ((inet_aton(cmd[1], &saddr) == 0)||
		inet_aton(cmd[2], &daddr) == 0){
		perror("bad ip addr\n");
		free(s);
		return;
	}
	s->sip = saddr.s_addr;
	s->dip = daddr.s_addr;
	s->sport = atoi(cmd[3]);
	s->dport = atoi(cmd[4]);
	if (strncmp(cmd[5], "tcp", sizeof("tcp"))==0)
		s->proto= 6;
	else if (strncmp(cmd[5], "udp", sizeof("udp")) == 0)
		s->proto= 11;
	else {
		perror("not a valid protocol type\n");
		free(s);
		return;
	}
	if (list_add(g_slist, (void *)s) != 0) {
		perror("add stream error!\n");
		free(s);
		return;
	}
	printf("[OK]\n");
}

void process_cmd_check(char **cmd)
{
	stream_t s;
	struct in_addr saddr, daddr;
	if ((inet_aton(cmd[1], &saddr) == 0)||
		inet_aton(cmd[2], &daddr) == 0){
		perror("bad ip addr\n");
		return;
	}
	s.sip = saddr.s_addr;
	s.dip = daddr.s_addr;
	s.sport = atoi(cmd[3]);
	s.dport = atoi(cmd[4]);
	if (strncmp(cmd[5], "tcp", sizeof("tcp"))==0)
		s.proto= 6;
	else if (strncmp(cmd[5], "udp", sizeof("udp")) == 0)
		s.proto= 11;
	else {
		perror("not a valid protocol type\n");
		return;
	}

	if (find_record(g_slist, &s, cmp) != 0) {
		printf("stream not found\n");
		return;
	}
	printf("stream find at\t%ld\n",g_slist->current_index);
}

/**
 * del current stream 
 */
void process_cmd_del(char **cmd, int token_cnt)
{
	if (token_cnt == 1) {/* delete current node */
		if (list_del(g_slist) != 0) {
			perror("del stream error!\n");
			return;
		}
	} else if (token_cnt == 6) { /* delete specified node */
	//not implement	
		stream_t s;
		struct in_addr saddr, daddr;
		if ((inet_aton(cmd[1], &saddr) == 0)||
			inet_aton(cmd[2], &daddr) == 0){
			perror("bad ip addr\n");
			return;
		}
		s.sip = saddr.s_addr;
		s.dip = daddr.s_addr;
		s.sport = atoi(cmd[3]);
		s.dport = atoi(cmd[4]);
		if (strncmp(cmd[5], "tcp", sizeof("tcp"))==0)
			s.proto= 6;
		else if (strncmp(cmd[5], "udp", sizeof("udp")) == 0)
			s.proto= 11;
		else {
			perror("not a valid protocol type\n");
			return;
		}
		if (find_record(g_slist, &s, cmp) != 0) {
			perror("stream not found\n");
			return;
		} else {
			if (list_del(g_slist) != 0) {
				perror("del stream error!\n");
				return;
			}
		}
	}
	printf("[OK]\n");
}

/**
 * valgrind may report "Invalid read xxx"
 * if there is only one token. because 
 * cmd[1]'s content is not defined.
 */
void process_cmd_show(char **cmd, int token_cnt)
{
	if (token_cnt == 1) {	/* no argument */
		get_current_stream(g_slist);
		return;
	}
	if (strncmp(cmd[1],"all", sizeof("all")) == 0)
		get_all_stream(g_slist);
	else if (strncmp(cmd[1], "first", sizeof("first")) == 0)
		get_first_stream(g_slist);
	else if (strncmp(cmd[1], "last", sizeof("last")) == 0)
		get_last_stream(g_slist);
	else
		get_current_stream(g_slist);

}

/**
 * split line into token
 * return token count.
 */
int parse_cmd_line(char *cl, char **argv, int max_argv)
{
	int argc;
	char *token;
	static const char *seps = " \t\r\n";

	token = strtok(cl, seps);
	for (argc = 0; token != NULL && argc < max_argv; argc++) {
		memset(argv[argc], '\0', 18);
		memcpy(argv[argc], token, strlen(token));
		token = strtok(NULL, seps);
	}
	return argc;
}

void __print_stream(stream_t *s)
{
	struct in_addr saddr, daddr;
	saddr.s_addr = s->sip;
	daddr.s_addr = s->dip;
	printf("    sip:      %s\n", inet_ntoa(saddr));
	printf("    dip:      %s\n", inet_ntoa(daddr));
	printf("    sport:    %d\n", s->sport);
	printf("    dport:    %d\n", s->dport);
	if (s->proto == 6) 
		printf("    protocol: TCP\n");
	else if (s->proto == 11)
		printf("    protocol: UDP\n");
}

void get_first_stream(list_t * list)
{
	if (list->head == NULL) {
		perror("stream list is null!");
		return;
	}
	__print_stream(get_first_record(g_slist));
}

void get_prev_stream(list_t * list)
{
	if (list->head == NULL) {
		perror("stream list is null!\n");
		return;
	}
	__print_stream(get_prev_record(g_slist));
}

void get_current_stream(list_t * list)
{
	if (list->head == NULL) {
		perror("stream list is null!\n");
		return;
	}
	__print_stream(get_current_record(g_slist));
}

void get_next_stream(list_t * list)
{
	if (list->head == NULL) {
		perror("stream list is null!");
		return;
	}
	__print_stream(get_next_record(g_slist));
}

void get_last_stream(list_t * list)
{
	if (list->head == NULL) {
		perror("stream list is null!");
		return;
	}
	__print_stream(get_last_record(g_slist));
}

void get_all_stream(list_t * list)
{
	unsigned long int i;
	if (list->head == NULL) {
		perror("stream list is null!\n");
		return;
	}
	node_t *tmp = g_slist->current;
	g_slist->current = g_slist->head;
	i = 1;	// first node
	while (g_slist->current != NULL) {
		printf("stream\t%ld\n", i);
		__print_stream(get_current_record(g_slist));
		g_slist->current = g_slist->current->next;
		i++;
	}
	g_slist->current = tmp;
}
void show_usage()
{
	char *MSG = "usage: ./test1 -[command]\n"
	    "-add	add a stream\n"
	    "-check	check a stream if it exist\n"
	    "-del	delete a stream\n"
	    "-exit	exit program\n"
	    "-import	import stream from file\n"
	    "-export	export stream to file\n"
	    "-show	show current stream\n"
	    "-size	show stream counter\n"
	    "-help	show help\n" "-version	show version\n";
	printf("%s\n", MSG);
}

void show_version()
{
	char *VERSION = "0.3";
	printf("\nversion: %s\n", VERSION);
}

void process_cmd_import(char **cmd)
{
	if (import_list(g_slist, cmd[1]) != 0)
		printf("import stream error!\n");
}

void process_cmd_export(char **cmd)
{
	char *path = cmd[1];
	printf("%s\n", cmd[1]);
	if (export_list(g_slist, path) != 0)
		printf("export stream error!\n");
}
int get_token_count(char *buffer, char delimit, int *count)
{
	char *ptr = NULL;
	char *ptr2 = NULL;

	*count = 0;
	ptr = buffer;
	ptr2 = buffer;
	while (*ptr) {
		if (*ptr == delimit) {
			if (ptr == ptr2) {
				return -1;
			}
			*count = *count + 1;
			ptr++;
			ptr2 = ptr;
		} else {
			ptr++;
		}
	}

	if (ptr == ptr2) {
		return -1;
	}
	*count = *count + 1;
	return 0;
}
char *stripwhite(char *string)
{
	register char *s, *t;

	for (s = string; isspace(*s); s++) {
	}

	if (*s == 0) {
		return s;
	}

	t = s + strlen(s) - 1;
	while (t > s && isspace(*t)) {
		t--;
	}
	*++t = '\0';

	return s;
}
void process_cmd_clear()
{
	if (list_clear(g_slist) !=0 ) {
		perror("clear stream error!\n");
		return;
	}
	printf("[OK]\n");
}

void sig_int(int a)
{
	list_destroy(&g_slist);
	exit(0);
}

4. Makefile

TARGET = test1
OBJS = db_list.o
OBJ_TEST1 = test1.o

PREFIX = /usr/local
LIBDIR = ${PREFIX}/lib
INCDIR = ${PREFIX}/include

LIB_STATIC = libdblist.a
LIB_DYNAMIC = libdblist.so
LIB = -L. -ldblist -lreadline -ltermcap
AR = ar rc
CC = gcc

SHARED = -shared -fPIC
CFLAGS = -g -Wall

all:
	make	clean
	make	dynamic 
	make 	static
	make	test
	
debug:


dynamic:$(OBJS)
	$(CC) $(SHARED) $(FLAGS) -o $(LIB_DYNAMIC) $(OBJS)

static:
	$(AR) $(LIB_STATIC) $(OBJS)

test:
	make $(TARGET)

$(OBJS):db_list.c db_list.h
	$(CC) -c $(CFLAGS) -fPIC db_list.c
#	$(CC) -c $(CFLAGS) db_list.c

$(OBJ_TEST1):test1.c db_list.h
	$(CC) -c $(CFLAGS)  test1.c

$(TARGET):$(OBJ_TEST1)
	$(CC) $(FLAGS) $(OBJ_TEST1) -o $(TARGET) $(LIB)
	
clean:
	-rm -f *.o *.so *.a test1
	
install:
	
uninstall:

5. 运行结果

[root@localhost dblist]# make 
make    clean
make[1]: Entering directory `/root/study/c/dblist'
rm -f *.o *.so *.a test1
make[1]: Leaving directory `/root/study/c/dblist'
make    dynamic 
make[1]: Entering directory `/root/study/c/dblist'
gcc -c -g -Wall -fPIC db_list.c
gcc -shared -fPIC  -o libdblist.so db_list.o
make[1]: Leaving directory `/root/study/c/dblist'
make    static
make[1]: Entering directory `/root/study/c/dblist'
ar rc libdblist.a db_list.o
make[1]: Leaving directory `/root/study/c/dblist'
make    test
make[1]: Entering directory `/root/study/c/dblist'
make test1
make[2]: Entering directory `/root/study/c/dblist'
gcc -c -g -Wall  test1.c
gcc  test1.o -o test1 -L. -ldblist -lreadline -ltermcap
make[2]: Leaving directory `/root/study/c/dblist'
make[1]: Leaving directory `/root/study/c/dblist'
[root@localhost dblist]# ls
data  db_list.c  db_list.h  db_list.o  libdblist.a  libdblist.so  Lindent  Makefile  test1  test1.c  test1.o
[root@localhost dblist]# ./test1 
CLI>help
usage: ./test1 -[command]
-add    add a stream
-check  check a stream if it exist
-del    delete a stream
-exit   exit program
-import import stream from file
-export export stream to file
-show   show current stream
-size   show stream counter
-help   show help
-version        show version

CLI>add 192.168.1.1 192.168.1.2 8888 9999 tcp
[OK]
CLI>show
    sip:      192.168.1.1
    dip:      192.168.1.2
    sport:    8888
    dport:    9999
    protocol: TCP
CLI>check 192.168.1.1 192.168.1.2 8888 9999 tcp
stream find at  1
CLI>size
stream counter: 1
CLI>
posted @ 2014-12-19 09:39  jelly.wd  阅读(202)  评论(0编辑  收藏  举报