Коммуникационный модуль Redis очень прост и удобен в использовании, его можно напрямую использовать в ваших собственных проектах, и его также очень полезно изучить.
Эта статья написана на основе исходного кода Redis 4.0.1, загрузка исходного кода Redis:GitHub.com/Антиэнтузиазм/Горячие…
файловая структура
Сетевой коммуникационный модуль Redis состоит из 8 файлов.
Эффект следующийдокумент | эффект |
---|---|
ae.c | Унифицированный epoll, evport, kqueue, выбор интерфейса обработки сетевых событий, реализация функций |
ae.h | Унифицированный epoll, evport, kqueue, выбор интерфейса обработки сетевых событий, прототип функции, определение общей структуры |
ae_epoll.c | Инкапсулируйте библиотеку обработки сетевых событий epoll в унифицированный интерфейс. |
ae_evport.c | Инкапсулируйте библиотеку обработки сетевых событий evport в унифицированный интерфейс. |
ae_kqueue.c | Инкапсулирует библиотеку обработки сетевых событий kqueue в единый интерфейс. |
ae_select.c | Инкапсулируйте выбранную библиотеку обработки сетевых событий в единый интерфейс |
Нижний интерфейс унифицированной сетевой библиотеки
Унифицированный интерфейс обработки сетевых событий выглядит следующим образом: ae_epoll.c, ae_evport.c, ae_kqueue.c, ae_select.c.
интерфейс | эффект |
---|---|
aeApiState | Структуры обмена данными, такие как fd и события, требуемые базовой сетевой библиотекой. |
aeApiCreate | Создайте сетевой дескриптор, например, дескриптор epoll, на этой основе для мониторинга и обработки сетевых событий. |
aeApiResize | Изменение размера контейнера события хранения сетевой библиотеки заключается в изменении размера массива событий структуры aeApiState. |
aeApiFree | Удалить общую структуру aeApiState |
aeApiAddEvent | Передайте операции чтения и записи сети fd в сетевую библиотеку для обработки, например, обработки этого epoll |
aeApiDelEvent | Когда вы удалите, будет использоваться для мониторинга сетевых операций с библиотеки FD, общий сервер к клиенту после написания данных, инициатива отключить клиента |
aeApiPoll | Опрос для получения события о том, что в сети происходят события чтения и записи ввода-вывода. |
aeApiName | Получите имя базовой сетевой библиотеки, такой как epool, kqueue и т. д. |
Верхний интерфейс единой сетевой библиотеки
Обратитесь к ae.h, ae.c, чтобы инкапсулировать общие структуры и функции.
Структура сетевых событий чтения и записи aeFileEvent
/* File event structure */
typedef struct aeFileEvent {
int mask; /* one of AE_(READABLE|WRITABLE) */
aeFileProc *rfileProc;
aeFileProc *wfileProc;
void *clientData;
} aeFileEvent;
Эта структура инкапсулирует функцию обработки Prototype сетевых данных чтения и записи и записи и данных с клиента.
Обработчик AefileProc - это прототип определений макроса, макроспределения относятся к следующему:
typedef void aeFileProc(
struct aeEventLoop *eventLoop,
int fd,
void *clientData,
int mask
);
При фактическом использовании функция обработки сетевых событий чтения и записи требуетНапишите свой собственный
Структура временного события aeTimeEvent
/* Time event structure */
typedef struct aeTimeEvent {
long long id; /* time event identifier. */
long when_sec; /* seconds */
long when_ms; /* milliseconds */
aeTimeProc *timeProc;
aeEventFinalizerProc *finalizerProc;
void *clientData;
struct aeTimeEvent *next;
} aeTimeEvent;
Это синхронизированное событие используется Redis для обработки фоновых синхронизированных задач, таких как обработка времени ожидания подключения клиента и операции отключения сервера.
активный фд
/* A fired event */
typedef struct aeFiredEvent {
int fd;
int mask;
} aeFiredEvent;
Это сеть fd, ожидающая чтения и записи, обычно представленная в виде массива.
Поле маски указывает, ждать ли чтения или записи, и соответствующие значения следующие
#define AE_READABLE 1
#define AE_WRITABLE 2
Основная структура верхнего интерфейса сетевой библиотеки aeEventLoop
/* State of an event based program */
typedef struct aeEventLoop {
int maxfd; /* highest file descriptor currently registered */
int setsize; /* max number of file descriptors tracked */
long long timeEventNextId;
time_t lastTime; /* Used to detect system clock skew */
aeFileEvent *events; /* Registered events */
aeFiredEvent *fired; /* Fired events */
aeTimeEvent *timeEventHead;
int stop;
void *apidata; /* This is used for polling API specific data */
aeBeforeSleepProc *beforesleep;
aeBeforeSleepProc *aftersleep;
} aeEventLoop;
Основные поля следующие *Список событий*events, индекс указывает fd, указывает функцию обратного вызова, которая будет выполняться при возникновении события чтения и записи сети fd * *fired ожидает чтения и записи списка fd, полученного опросом, например epoll, полученного epoll_wait * beforesleep выполняется до epoll_wait * aftersleep выполняется после epoll_wait
Работа с функциями, связанными с aeEventLoop
В основном для работы со структурой aeEventLoop, вот несколько основных функций, например
aeCreateEventLoop()
Эта функция в основном создает структуру aeEventLoop и выделяет пространство содержимого для событий и запускает их в соответствии с параметром setsize. Затем вызовите aeApiCreate для управления базовой сетевой библиотекой, такой как epoll_create() из epoll, и сохраните ее в атрибуте apidata aeEventLoop.
aeMain()
В основном, чтобы запустить бесконечный цикл, опросить активный fd, если epoll, нижний уровень вызывает epoll_wait, чтобы получить доступный для чтения и записи fd: ae.c::aeMain() -> ae.c::aeProcessEvents() -> ae_epoll.c :: aeApiPool() -> ae_epoll.c::epoll_wait()
aeCeateFileEvent()
Зарегистрируйте network fd в базовой сетевой библиотеке и зарегистрируйте бизнес-функцию обратного вызова, которая должна выполняться при возникновении события чтения и записи. Возьмите epoll в качестве примера, шаги для вызова epoll: ae.c::aeCreateFileEvent() -> ae_epoll.c::aeApiAddEvent() -> epoll_ctl()
anet.h & anet.c
Он в основном инкапсулирует операции сокетов, скрывает различия в базовых операциях сокетов в системе и предоставляет улучшенные API, такие как создание серверов tcp и т. д.
Давайте посмотрим на процесс создания tcp-сервера здесь.
anetTcpServer()
anet.c::anetTcpServer() -> anet.c::_anetTcpServer() -> <sys/socket.h>::socket() -> anet.c::anetListen() -> <sys/socket.h>::listen()
Основной код заключается в вызове функции прослушивания библиотеки системных сокетов для установки tcp-сервера.
Пример
Здесь используйте ae.h и anet.h для создания простого tcp-сервера и отправки клиенту «Hello World».
код показывает, как показано ниже:
#include <stdio.h>
#include <zconf.h>
#include "../src/ae.h"
#include "../src/anet.h"
char myerr[ANET_ERR_LEN] = {0};
void acceptFd(struct aeEventLoop *eventLoop, int fd, void *clientdata, int mask) {
char myerr[ANET_ERR_LEN] = {0};
printf("获取客户端连接的fd.\n");
char ip[20] = {0};
int port = 0;
int clientfd = anetTcpAccept(myerr, fd, ip, sizeof(ip), &port);
if (clientfd == AE_ERR) {
printf("获取客户端连接的fd异常!! \n");
return;
}
printf("客户端ip %s port %d \n", ip, port);
int ret = anetNonBlock(myerr, clientfd);
if (ret == ANET_OK) {
printf("客户端事件非阻塞处理设置成功\n\n");
}
anetEnableTcpNoDelay(myerr, clientfd);
write(clientfd,"Hello Client!\n",14);
}
int main() {
aeEventLoop *eventLoop = aeCreateEventLoop(1024);
if(!eventLoop){
return 1;
}
int fd = anetTcpServer(myerr, 8080, "0.0.0.0", 511);
if (fd != ANET_ERR) {
anetNonBlock(NULL, fd);
if (aeCreateFileEvent(eventLoop, fd, AE_READABLE, acceptFd, NULL)) {
printf("注册tcp服务器接收客户端连接的事件处理函数异常");
}
}
printf("服务器在 0.0.0.0:8080 端口监听了! \n");
aeMain(eventLoop);
aeDeleteEventLoop(eventLoop);
return 0;
}
Затем компилируем и запускаем, при компиляции можно использовать gcc, эффект следующий
gcc -o myserver src/ae.c src/anet.c src/zmalloc.c myserver.c
Можно проверить через телнет
Вы можете видеть, что клиент успешно получил сообщение Hello World, возвращенное сервером.некоторые замечания
Если стандартную библиотеку c не удается найти в Mac OS 10.14.5, необходимо установить этот файл: /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg