Libevent中的timeout事件是使用最小堆來管理維護的.代碼位于<minheap-internal.h>.
源碼來源:
https://github.com/libevent/libevent/blob/release-2.1.8-stable/minheap-internal.h本篇在第2篇的基礎之上進行優化更新,加上類似muduo活塞式的buffer。
本篇實作Linux網絡庫epoll+時間堆+buffer實作高性能伺服器。
完整的工程下載下傳:
https://download.csdn.net/download/libaineu2004/104687141、CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
PROJECT(min_heap_libevent_epoll_buf)
AUX_SOURCE_DIRECTORY(. SRC_LIST)
ADD_EXECUTABLE(${PROJECT_NAME} ${SRC_LIST})
2、buffer.h
#ifndef MYREDISNET_AEBUFFER_H
#define MYREDISNET_AEBUFFER_H
/// 《Linux多線程服務端程式設計:使用muduo C++網絡庫》陳碩著 7.4章節,P204
/// https://github.com/chenshuo/muduo
/// muduo buf:A buffer class modeled after org.jboss.netty.buffer.ChannelBuffer
///
/// @code
/// +-------------------+------------------+------------------+
/// | prependable bytes | readable bytes | writable bytes |
/// | | (CONTENT) | |
/// +-------------------+------------------+------------------+
/// | | | |
/// 0 <= readerIndex <= writerIndex <= size
///
/// @endcode
//#include "zmalloc.h"//不能直接包含reids這個頭檔案,編譯會報錯 basic_string.h:2423:7: error: ‘__str’ was not declared in this scope
//#include "myjemalloc.h"//要用這個
#include <sys/types.h>
//no use jemalloc,only libc
#define zmalloc malloc
#define zfree(p) if (p) { free(p); }
#define zrealloc realloc
#define DEFAULT_BUFF_SIZE 1024
typedef struct {
unsigned char *buff;
size_t size;
size_t read_idx;
size_t write_idx;
} buffer_t;
buffer_t *alloc_buffer();
void free_buffer(buffer_t *buffer);
void check_buffer_size(buffer_t *buffer, size_t avlid_size);
size_t get_readable_size(buffer_t *buffer);
size_t get_writeable_size(buffer_t *buffer);
#endif //MYREDISNET_AEBUFFER_H
3、buffer.c4、client.h
#ifndef CLIENT_H
#define CLIENT_H
#include <stdio.h>
#include <stdint.h> //eg. uint64_t
#include "buffer.h"
typedef struct {
int fd;
int epollfd;
int timerId;
uint64_t last_recv_tick;
buffer_t *read_buffer;
buffer_t *write_buffer;
} client_t;
typedef struct fileEvent {
client_t *clientData;
} fileEvent;
extern fileEvent *fileev;
extern client_t *alloc_client();
extern uint64_t get_tick_count();
extern void free_client(client_t *client);
extern void create_fileEvent(int setsize);
extern void destroy_fileEvent(int setsize);
#endif // CLIENT_H
5、client.c
#include "client.h"
fileEvent *fileev = NULL;
uint64_t get_tick_count() //come from /teamtalk/util.cpp
{
#ifdef _WIN32
LARGE_INTEGER liCounter;
LARGE_INTEGER liCurrent;
if (!QueryPerformanceFrequency(&liCounter))
return GetTickCount();
QueryPerformanceCounter(&liCurrent);
return (uint64_t)(liCurrent.QuadPart * 1000 / liCounter.QuadPart);
#else
struct timeval tval;
uint64_t ret_tick;
gettimeofday(&tval, NULL);
ret_tick = tval.tv_sec * 1000L + tval.tv_usec / 1000L;
return ret_tick;
#endif
}
client_t *alloc_client()
{
client_t * client = zmalloc(sizeof(client_t));
if (client == NULL) {
goto err;
}
client->fd = -1;
client->timerId = -1;
client->last_recv_tick = get_tick_count();
client->read_buffer = alloc_buffer();
client->write_buffer = alloc_buffer();
if (client->read_buffer == NULL || client->write_buffer == NULL) {
goto err;
}
return client;
err:
if (client) {
free_client(client);
}
return NULL;
}
void free_client(client_t *client)
{
if (client) {
if (client->fd > 0) {
close(client->fd);
}
free_buffer(client->read_buffer);
free_buffer(client->write_buffer);
zfree(client);
}
}
void create_fileEvent(int setsize)
{
fileev = zmalloc(sizeof(fileEvent) * setsize);
}
void destroy_fileEvent(int setsize)
{
int i = 0;
for (i = 0; i < setsize; i++)
{
if (fileev->clientData != NULL)
{
free_client(fileev->clientData);
}
}
zfree(fileev);
}
6、minheap-event-firecat.h
#ifndef MINHEAPEVENTFIRECAT_H
#define MINHEAPEVENTFIRECAT_H
#include <sys/time.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
//come from https://github.com/libevent/libevent/blob/release-2.1.8-stable/mm-internal.h
#define mm_malloc(sz) malloc(sz)
#define mm_calloc(n, sz) calloc((n), (sz))
#define mm_strdup(s) strdup(s)
#define mm_realloc(p, sz) realloc((p), (sz))
#define mm_free(p) free(p)
//come from https://github.com/libevent/libevent/blob/release-2.1.8-stable/include/event2/util.h
#define evutil_timercmp(tvp, uvp, cmp) \
(((tvp)->tv_sec == (uvp)->tv_sec) ? \
((tvp)->tv_usec cmp (uvp)->tv_usec) : \
((tvp)->tv_sec cmp (uvp)->tv_sec))
#define evutil_timersub(tvp, uvp, vvp) \
do { \
(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
(vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
if ((vvp)->tv_usec < 0) { \
(vvp)->tv_sec--; \
(vvp)->tv_usec += 1000000; \
} \
} while (0)
#define evutil_timeradd(tvp, uvp, vvp) \
do { \
(vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \
(vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \
if ((vvp)->tv_usec >= 1000000) { \
(vvp)->tv_sec++; \
(vvp)->tv_usec -= 1000000; \
} \
} while (0)
//come from https://github.com/libevent/libevent/blob/release-2.1.8-stable/include/event2/event_struct.h
struct event
{
/* for managing timeouts */
union {
//TAILQ_ENTRY(event) ev_next_with_common_timeout;
int min_heap_idx;
} ev_timeout_pos;
unsigned int timer_id;
struct timeval ev_interval;
struct timeval ev_timeout;
int ev_exe_num;
int (*ev_callback)(void *arg);
int ev_arg;
int ev_res; /* result passed to event callback */
int ev_flags;
};
//static inline void gettime(struct timeval *tm);
static void gettime(struct timeval *tm)
{
gettimeofday(tm, NULL);
}
//come from redis src "ae.c"
static void aeGetTime(long *seconds, long *milliseconds)
{
struct timeval tv;
gettimeofday(&tv, NULL);
*seconds = tv.tv_sec;
*milliseconds = tv.tv_usec/1000;
}
#endif // MINHEAPEVENTFIRECAT_H