幫朋友寫的, 很簡單...
還是貼出來, 希望能對看客有所幫助, 也希望看客能對我有所幫助...
謝謝.
#include <stdio.h>
#include <stdlib.h>
/**
* author: selfimpr
* blog: http://blog.csdn.net/lgg201
* mail: [email protected]
*/
struct UserPool {
struct User *head; /* 所分配存儲空間首指針 */
struct User *useable; /* 當前未使用的存儲空間首指針 */
struct User *free; /* 空閒鏈表首指針 */
int used; /* 內存池中已在線的用戶數 */
int alloced; /* 分配的內存池大小 */
}; /* 用戶內存池 */
struct User {
int uid; /* 用戶標識 */
int fd; /* 文件描述符 */
struct Map *map_p; /* 所在地圖 */
int map_i; /* 在所在地圖用戶數組中的下標 */
struct User *next; /* 作爲內存池空閒鏈表時的構造指針 */
struct UserPool *pool; /* 所在內存池 */
int isfree; /* 是否空閒(1表示用戶已離線, 空間可重用) */
int pool_i; /* 在內存池中的下標 */
}; /* 用戶 */
struct Map {
struct User **users; /* 用戶數組 */
int alloced; /* 已分配用戶數組大小 */
int used; /* 已使用用戶數組大小 */
}; /* 地圖 */
struct HashTableElement {
unsigned int key; /* 鍵 */
void *value; /* 值 */
struct HashTableElement *next; /* 下一個節點 */
}; /* 哈希表元素 */
struct HashTable {
struct HashTableElement *elements; /* 存儲數據的鏈表數組 */
unsigned int size; /* 哈希表大小 */
}; /* 哈希表 */
/* 創建哈希表 */
struct HashTable *hash_table_create(unsigned int size) {
struct HashTable *ht;
ht = (struct HashTable *)malloc(sizeof(struct HashTable));
if ( ht == NULL )
goto failed;
ht->size = size;
ht->elements = (struct HashTableElement *)calloc(size, sizeof(struct HashTableElement));
if ( ht->elements == NULL )
goto failed;
return ht;
failed:
printf("hash_table_create failed\n");
if ( ht != NULL ) {
if ( ht->elements != NULL )
free(ht->elements);
free(ht);
}
return NULL;
}
/* 向哈希表中寫入或更新數據 */
int hash_table_add_or_update(struct HashTable *ht, unsigned int k, void *value) {
struct HashTableElement *h, *e, *n;
h = &(ht->elements[k % ht->size]);
e = h->next;
if ( e == NULL ) {
e = h;
goto insert;
}
do {
if ( e->key == k )
goto update;
else
e = e->next;
} while ( e->next != NULL );
insert:
n = (struct HashTableElement *)calloc(1, sizeof(struct HashTableElement));
n->key = k;
n->value = value;
e->next = n;
return (0);
update:
e->value = value;
return (0);
}
/* 在哈希表中查找數據 */
struct HashTableElement *hash_table_find(struct HashTable *ht, unsigned int k) {
struct HashTableElement *h, *e;
h = &(ht->elements[k % ht->size]);
e = h->next;
if ( e == NULL )
goto failed;
do {
if ( e->key == k )
return e;
else
e = e->next;
} while ( e != NULL );
failed:
return NULL;
}
/* 從哈希表中刪除數據 */
int hash_table_delete(struct HashTable *ht, unsigned int k) {
struct HashTableElement *p, *e;
p = &(ht->elements[k % ht->size]);
e = p->next;
if ( e == NULL )
goto failed;
do {
if ( e->key == k ) {
p->next = e->next;
free(e);
return (0);
} else {
p = e;
e = e->next;
}
} while ( e != NULL );
failed:
return (-1);
}
/* 輸出哈希表數據 */
void hash_table_dump(struct HashTable *ht, char *(*to_string)(void *)) {
int i;
struct HashTableElement *h, *e;
for ( i = 0; i < ht->size; i ++ ) {
h = &(ht->elements[i]);
e = h->next;
while ( e != NULL ) {
printf("%d: %s\n", e->key, to_string(e->value));
e = e->next;
}
}
}
/* 用於哈希表測試用例的字符串轉換函數 */
char *empty_to_string(void *v) {
return (char *)v;
}
/* 哈希表測試用例 */
void hash_table_test() {
struct HashTable *ht;
ht = hash_table_create((unsigned int)30);
hash_table_add_or_update(ht, 1, (void *)"one");
hash_table_add_or_update(ht, 2, (void *)"two");
hash_table_add_or_update(ht, 3, (void *)"three");
hash_table_add_or_update(ht, 4, (void *)"four");
hash_table_add_or_update(ht, 1, (void *)"first-one");
hash_table_add_or_update(ht, 2, (void *)"second-two");
hash_table_add_or_update(ht, 3, (void *)"third-three");
hash_table_add_or_update(ht, 4, (void *)"forth-four");
hash_table_delete(ht, 3);
hash_table_dump(ht, empty_to_string);
}
/* 地圖創建 */
struct Map *map_create(int num) {
struct Map *map;
map = (struct Map *) malloc(sizeof(struct Map));
if ( map == NULL )
goto failed;
map->users = (struct User **) calloc(num, sizeof(struct User *));
map->alloced = num;
map->used = 0;
return map;
failed:
if ( map != NULL )
free(map);
return NULL;
}
/* 用戶進入地圖 */
int map_user_enter(struct Map *map, struct User *user) {
int i;
for ( i = 0; i < map->alloced; i ++ ) {
if ( map->users[i] == NULL ) {
map->users[i] = user;
user->map_p = map;
user->map_i = i;
map->used ++;
return (0);
}
}
return (-1);
}
/* 用戶離開地圖 */
int map_user_leave(struct User *user) {
user->map_p->users[user->map_i] = NULL;
user->map_p->used --;
user->map_i = 0;
user->map_p = NULL;
}
/* 創建用戶內存池 */
struct UserPool *user_pool_create(int size) {
struct UserPool *pool;
pool = (struct UserPool *)malloc(sizeof(struct UserPool));
pool->head = (struct User *)calloc(size, sizeof(struct User));
pool->useable = pool->head;
pool->free = NULL;
pool->alloced = size;
pool->used = 0;
return (pool);
failed:
if ( pool != NULL ) {
if ( pool->head != NULL )
free(pool->head);
free(pool);
}
return (NULL);
}
/* 從內存池分配一個用戶的空間 */
struct User *user_pool_alloc_user(struct UserPool *pool) {
struct User *u;
/* TODO 此處應該是內存池擴展邏輯, 比較複雜, 未實現 */
/* 從空閒鏈表中分配 */
if ( pool->free != NULL ) {
u = pool->free;
u->isfree = 0;
pool->free = pool->free->next;
pool->used ++;
return u;
}
/* 從未使用空間中分配 */
u = pool->useable;
u->pool = pool;
u->pool_i = pool->useable - pool->head;
pool->useable ++;
pool->used ++;
return u;
}
/* 從內存池中釋放一個用戶 */
void user_pool_free_user(struct User *user) {
struct UserPool *pool;
pool = user->pool;
user->isfree = 1;
/* 將被釋放的空間放入空閒鏈表 */
user->next = pool->free;
pool->free = user;
/* 更新用戶計數 */
pool->used --;
}
struct Map **maps; /* 所有的地圖 */
struct HashTable *user_ht; /* 用戶哈希表 */
struct UserPool *user_pool; /* 用戶內存池 */
/* 地圖數量 */
int map_num = 1;
/* 地圖最大人數 */
int map_user_num = 10;
/* 總人數上限 */
int user_num = 100;
/* 遊戲初始化 */
int game_init() {
int i;
/* 地圖初始化 */
maps = (struct Map **)calloc(map_num, sizeof(struct Map *));
for ( i = 0; i < map_num; i ++ ) {
maps[i] = map_create(map_user_num);
}
/* 用戶存儲初始化 */
user_pool = user_pool_create(user_num);
/* 用戶哈希表初始化 */
user_ht = hash_table_create(user_num);
}
/* 用戶登入 */
void user_login(int uid, int fd) {
struct User *user;
/* 在內存池中爲用戶分配空間 */
user = user_pool_alloc_user(user_pool);
/* 初始化用戶基本信息 */
user->uid = uid;
user->fd = fd;
/* 用戶進入地圖 */
map_user_enter(maps[0], user);
/* 將用戶放入哈希表便於查找 */
hash_table_add_or_update(user_ht, uid, (void *)user);
}
/* 用戶登出 */
void user_logout(int uid) {
struct HashTableElement *e;
struct User *user;
/* 從哈希表中查找用戶 */
e = (struct HashTableElement *)hash_table_find(user_ht, uid);
user = (struct User *)e->value;
/* 用戶離開地圖 */
map_user_leave(user);
/* 從內存池中釋放用戶 */
user_pool_free_user(user);
/* 從哈希表中移除用戶 */
hash_table_delete(user_ht, uid);
}
/* 將用戶轉換爲字符串 */
char *user_to_string(void *value) {
static char buffer[1024];
struct User *user;
user = (struct User *)value;
sprintf(buffer, "uid: %d, fd: %d, map_p: %p, map_i: %d, pool: %p, pool_i: %d, ptr: %p, next: %p",
user->uid, user->fd, user->map_p, user->map_i, user->pool, user->pool_i, user, user->next);
return buffer;
}
int main(int argc, char *argv[]) {
/* 初始化遊戲 */
game_init();
int i;
struct User *tmp;
/* 登入十個用戶 */
for ( i = 1; i <= 10; i ++ )
user_login(i, i);
/* 登出三個用戶 */
user_logout(2);
user_logout(3);
user_logout(4);
/* 打印在線用戶信息 */
hash_table_dump(user_ht, user_to_string);
/* 打印用戶內存池的空閒鏈表 */
printf("\nfree elements:\n");
for ( tmp = user_pool->free; tmp != NULL; tmp = tmp->next )
printf("%s\n", user_to_string((void *)tmp));
}