如題,redis網絡庫是基于單程序單線程的機制實作,簡單高效。可用直接将它提取出來使用。Redis網絡庫是一個單線程EPOLL模型的網絡庫,和Memcached使用的libevent相比,它沒有那麼龐大,代碼一共2000多行,是以比較容易分析。本篇拿出了Redis網絡部分的代碼,添加了應用層buffer,讓它現在變成了一個可以實作tcp通信的程式。
Redis網絡庫是一個單線程EPOLL模型,也就是說接收連接配接和處理讀寫請求包括定時器任務都被這一個線程包攬,真的是又當爹又當媽,但是效率一定比多線程差嗎?不見得。
單線程的好處有:
1:避免線程切換帶來的上下文切換開銷。
2:單線程避免了鎖的争用。
3:對于一個記憶體型資料庫,如果不考慮資料持久化,也就是讀寫實體磁盤,不會有阻塞操作,記憶體操作是非常快的。
#The network library from redis v4.0.9 --
https://github.com/antirez/redis#把源碼以下檔案提取出來即可使用,無需作任何修改。
#/redis-unstable/src/ae.c
#/redis-unstable/src/ae.h
#/redis-unstable/src/ae_epoll.c
#/redis-unstable/src/ae_evport.c
#/redis-unstable/src/ae_kqueue.c
#/redis-unstable/src/ae_select.c
#/redis-unstable/src/anet.c
#/redis-unstable/src/anet.h
#/redis-unstable/src/atomicvar.h
#/redis-unstable/src/config.h
#/redis-unstable/src/fmacros.h
#/redis-unstable/src/zmalloc.c
#/redis-unstable/src/zmalloc.h
根據記憶體配置設定器的使用不同,差別為:
完整的工程源碼下載下傳(malloc使用原生的libc):
https://download.csdn.net/download/libaineu2004/10468733 完整的工程源碼下載下傳(malloc使用jemalloc): https://download.csdn.net/download/libaineu2004/10468734 如果不清楚libc和jemalloc的概念,請看 http://blog.csdn.net/libaineu2004/article/details/79400357 jemalloc的源碼下載下傳和編譯: https://blog.csdn.net/libaineu2004/article/details/79402103 CMakeLists.txt(使用libc)cmake_minimum_required(VERSION 2.8)
#The network library from redis v4.0.9 -- https://github.com/antirez/redis
#No changes were made.
#/redis-unstable/src/ae.c
#/redis-unstable/src/ae.h
#/redis-unstable/src/ae_epoll.c
#/redis-unstable/src/ae_evport.c
#/redis-unstable/src/ae_kqueue.c
#/redis-unstable/src/ae_select.c
#/redis-unstable/src/anet.c
#/redis-unstable/src/anet.h
#/redis-unstable/src/atomicvar.h
#/redis-unstable/src/config.h
#/redis-unstable/src/fmacros.h
#/redis-unstable/src/zmalloc.c
#/redis-unstable/src/zmalloc.h
project(myRedisNetDemo)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -g")
set(REDIS_SRC ./redis_network/ae.c ./redis_network/anet.c ./redis_network/zmalloc.c)
include_directories(./redis_network) #https://github.com/antirez/redis
add_executable(${PROJECT_NAME} example_firecat.c buffer.c ${REDIS_SRC})
CMakeLists.txt(使用jemalloc)
cmake_minimum_required(VERSION 2.8)
#The network library from redis v4.0.9 -- https://github.com/antirez/redis
#No changes were made.
#/redis-unstable/src/ae.c
#/redis-unstable/src/ae.h
#/redis-unstable/src/ae_epoll.c
#/redis-unstable/src/ae_evport.c
#/redis-unstable/src/ae_kqueue.c
#/redis-unstable/src/ae_select.c
#/redis-unstable/src/anet.c
#/redis-unstable/src/anet.h
#/redis-unstable/src/atomicvar.h
#/redis-unstable/src/config.h
#/redis-unstable/src/fmacros.h
#/redis-unstable/src/zmalloc.c
#/redis-unstable/src/zmalloc.h
project(myRedisNetDemo)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -g")
set(REDIS_SRC ./redis_network/ae.c ./redis_network/anet.c ./redis_network/zmalloc.c)
find_library(JEMALLOC_LIB libjemalloc.so /usr/local/lib)
IF (NOT JEMALLOC_LIB)
MESSAGE(FATAL_ERROR "libjemalloc not found")
ENDIF(NOT JEMALLOC_LIB)
SET(JEMALLOC_INCLUDE_DIR /usr/include/jemalloc)
SET(JEMALLOC_LIB /usr/local/lib)
INCLUDE_DIRECTORIES(./redis_network) #https://github.com/antirez/redis
INCLUDE_DIRECTORIES(${JEMALLOC_INCLUDE_DIR})
LINK_DIRECTORIES(${JEMALLOC_LIB})
#ADD_EXECUTABLE必須在TARGET_LINK_LIBRARIES前面,否則會報錯
ADD_EXECUTABLE(${PROJECT_NAME} example_firecat.c buffer.c ${REDIS_SRC})
TARGET_LINK_LIBRARIES(${PROJECT_NAME} jemalloc)
buffer.h,關注頭檔案包含:
#include "zmalloc.h"//libc要用這個
//#include "redis_network/zmalloc.h"//或者libc要用這個
//#include "myjemalloc.h"//jemalloc要用這個
#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"//不能直接包含這個頭檔案,編譯會報錯 basic_string.h:2423:7: error: ‘__str’ was not declared in this scope
#include "myjemalloc.h"//要用這個
#include <sys/types.h>
#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
myjemalloc.h -- 本人自定義的頭檔案
#ifndef __MYJEMALLOC_H
#define __MYJEMALLOC_H
#include <jemalloc/jemalloc.h>
#define zmalloc(size) je_malloc(size)
#define zcalloc(count,size) je_calloc(count,size)
#define zrealloc(ptr,size) je_realloc(ptr,size)
#define zfree(ptr) je_free(ptr)
#define zmallocx(s
ize,flags) je_mallocx(size,flags)
#define zdallocx(ptr,flags) je_dallocx(ptr,flags)
#endif
buffer.c
#include "buffer.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
buffer_t *alloc_buffer()
{
buffer_t *buffer = zmalloc(sizeof(buffer_t));
if (buffer == NULL) {
goto err;
}
buffer->buff = zmalloc(DEFAULT_BUFF_SIZE);
buffer->size = DEFAULT_BUFF_SIZE;
buffer->read_idx = 0;
buffer->write_idx = 0;
return buffer;
err:
if (buffer) {
zfree(buffer->buff);
buffer->buff = NULL;
zfree(buffer);
buffer = NULL;
}
return NULL;
}
void free_buffer(buffer_t *buffer)
{
if (buffer) {
zfree(buffer->buff);
buffer->buff = NULL;
zfree(buffer);
buffer = NULL;
}
}
void check_buffer_size(buffer_t *buffer, size_t avlid_size)
{
if (buffer->read_idx > DEFAULT_BUFF_SIZE) {
size_t data_len = get_readable_size(buffer);
memmove(buffer->buff, buffer->buff + buffer->read_idx, data_len);
buffer->read_idx = 0;
buffer->write_idx = data_len;
}
if (get_writeable_size(buffer) < avlid_size) {
size_t new_size = buffer->size + avlid_size;
buffer->buff = zrealloc(buffer->buff, new_size);
buffer->size = new_size;
}
}
size_t get_readable_size(buffer_t *buffer)
{
assert(buffer->size >= buffer->write_idx);
assert(buffer->read_idx <= buffer->write_idx);
return buffer->write_idx - buffer->read_idx;
}
size_t get_writeable_size(buffer_t *buffer)
{
assert(buffer->size >= buffer->write_idx);
assert(buffer->read_idx <= buffer->write_idx);
return buffer->size - buffer->write_idx;
}