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/10468714
1、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