Русский
Русский
English
Статистика
Реклама

Знакомство с exsc (EXtensible Server Core). Часть 1

ПРИВЕТСТВИЕ
image
Всем привет! Хочу поделиться с общественностью библиотекой, на основе которой в данный момент множество серверов, обслуживают тысячи клиентов в различных серверных системах. exsc (EXtensible Server Core) это библиотека, написанная на языке C и позволяет в рамках одного приложения, иметь один или несколько серверных потоков. Каждый серверный поток способен обслужить большое количество клиентов. Хотя библиотеку, можно использовать в модели типа запрос-ответ, в первую очередь она была рассчитана на поддержание постоянного соединения с большим количеством клиентов и обменом сообщений в реальном времени. Поскольку я и сам люблю взять готовый HelloWorld проект, скомпилировать его и посмотреть как всё работает, то в конце статьи я выложу ссылку на такой проект.

ДОКУМЕНТАЦИЯ

Многие операции делаются для определённого соединения. В рамках данной библиотеки за соединение отвечает структура exsc_excon. У этой структуры есть следующие поля:

ix индекс соединения. Это порядковый номер соединения, которое было свободно в момент подключения клиента.
id идентификатор соединения. Это уникальный номер соединения. В отличие от индекса он не повторяется.
addr IP адрес клиента
name имя соединения. Несколько соединений можно назвать одним именем и затем отослать какое-либо сообщение всем соединениям с одинаковым именем (смотрите функцию exsc_sendbyname).

Инициализация ядра

Для того, чтобы работать с ядром, нам необходимо его инициализировать с помощью функции
void exsc_init(int maxsrvcnt);
Параметр maxsrvcnt сообщает ядру, сколько серверных потоков мы будем использовать в рамках нашего приложения.

Запуск серверного потока

Далее нам нужно запустить серверный поток с помощью функции
int exsc_start(uint16_t port, int timeout, int timeframe, int recvbufsize, int concnt,
void newcon(struct exsc_excon excon),
void closecon(struct exsc_excon excon),
void recv(struct exsc_excon excon, char *buf, int bufsize),
void ext());


port порт который будет прослушивать серверный поток.

timeout указывает сколько времени серверный поток будет ожидать какой-либо активности от клиента. Если в течении этого времени клиент не прислал ни одного сообщения, то серверный поток закрывает такое соединение. Поэтому если мы хотим держать постоянную связь и выставили этот параметр на пример 30 секунд, то необходимо раз в 10-15 секунд присылать какое-либо сообщение типа ping.

timeframe временные рамки, за которое мы позволяем выполнить запрос.Так на пример, если это значение выставлено на 100 миллисекунд и серверный поток обработал все текущие запросы от пользователей за 10 секунд, то он оставшиеся 90 миллисекунд оставит процессору для выполнения других задач. Таким образом, чем меньше это значение, тем быстрее серверный поток будет обрабатывать запросы, но тем больше он нагрузит процессор.

recvbufsize размер буфера который серверный поток будет вычитывать за один раз.

concnt максимальное количество соединений с которым серверный поток работает одновременно.

newcon сallback функция, которая будет отрабатывать каждый раз когда будет подключаться новый клиент. В параметры этой функции будет передаваться соединение клиента который подключился.

closecon сallback функция, которая будет отрабатывать каждый раз когда будет закрываться неактивное подключение. В параметры этой функции будет передаваться соединение клиента который отключился.

recv сallback функция, которая будет вызываться когда клиент будет присылать пакеты. В параметры этой функции будет передаваться соединение клиента от которого пришли данные, указатель на данные и размер буфера с данными.

ext сallback функция, которая будет вызываться каждый проход цикла серверного потока. Эта функция сделана для расширения функционала ядра. На пример сюда можно подвязать обработку таймеров.

Функция exsc_start возвращает дескриптор серверного потока, который понадобится для вызова некоторых функций.

Отправка сообщений
За отправку сообщений отвечает функция
void exsc_send(int des, struct exsc_excon *excon, char *buf, int bufsize);
Эта функция потокобезопасная (её можно вызывать её из любого потока). В качестве параметров необходимо передать ей дескриптор серверного потока (который мы получили как возвращаемое значение функции exsc_start), соединение на которое мы хотим отправить сообщение, указатель на буфер с сообщением и размер буфера.

Так же мы имеем возможность отправить сообщение группе клиентов. Для этого есть функция
void exsc_sendbyname(int des, char *conname, char *buf, int bufsize);
Она аналогична функции exsc_send, за исключением второго параметра, в который передаётся имя подключений которым будет отправлено сообщение.

Задание имени подключения
Для тог, чтобы в будущем как то дополнительно идентифицировать подключение, либо хранить вместе с подключением некоторую информацию о нём, либо отправлять сообщения группе клиентов, используется функция
void exsc_setconname(int des, struct exsc_excon *excon, char *name);
Эта функция потокобезопасная. В качестве первого параметра передаётся дескриптор серверного потока, вторым параметром передаём само подключение и третьим параметром передаём имя этого подключения.

Подключение серверного потока к другому серверу
Иногда, серверная логика требует того, чтобы подключиться к другому серверу, для того чтобы запросить или передать какие либо данные. Для таких задач была введена функция, которая создаёт такое подключение.
void exsc_connect(int des, const char *addr, uint16_t port, struct exsc_excon *excon);
Эта функция потокобезопасная. В качестве параметров нам необходимо передать дескриптор серверного потока, адресс сервера к которому нам необходимо подключиться, потр сервера к которому нам необходимо подключиться и последним параметром мы передаём указатель на соединение с помощью которого мы в дальнейшем сможем вызывать другие функции библиотеки. Стоит отметить что нам нет необходимости дожидаться, пока подключение состоится. Мы можем вызвать функции exsc_connect и exsc_send одну за другой и система сама проследит за тем, чтобы сообщение было отослано сразу после того как сможет подключиться к удалённому серверу.

ПРИМЕР СЕРВЕРА С КОММЕНТАРИЯМИ

#include <stdio.h>  // fgets#include <string.h> // strcmp#include "../exnetwork/exsc.h" // подключаем исходники ядраint g_des; // дескриптор серверного потока// ловим новое подключениеvoid exsc_newcon(struct exsc_excon con){    printf("the connection was open  %s\n", con.addr);}// подключение закрываетсяvoid exsc_closecon(struct exsc_excon con){    printf("the connection was closed  %s\n", con.addr);}// принимаем сообщение от клиентаvoid exsc_recv(struct exsc_excon con, char *buf, int bufsize){    char msg[512] = { 0 };    memcpy(msg, buf, bufsize);    printf("receive data from %s\n%s\n", con.addr, msg);    if (strcmp(msg, "say hello") == 0)    {        strcpy(msg, "hello");        exsc_send(g_des, &con, msg, strlen(msg));    }}void exsc_ext(){}int main(){    printf("server_test_0 is started\n");    exsc_init(2); // инициализируем ядро с расчётом на два серверных потока    // запускаем серверный поток на порту 7777    // он будет держать неактивные соединения 30 секунд    // будет обрабатывать входящие сообщения в рамках 10 миллисекунд    // размер буфера для приёма задаём 1024 байта    // максимальное количество подключений ограничиваем до 10000    g_des = exsc_start(7777, 30, 10, 1024, 10000, exsc_newcon, exsc_closecon, exsc_recv, exsc_ext);    // тормозим главный поток, чтобы программа не завершилась раньше времени    // программа завершится когда мы введём команду exit и нажмём клавишу ENTER    while (1)    {        const int cmdmaxlen = 256;        char cmd[cmdmaxlen];        fgets(cmd, cmdmaxlen, stdin);        if (strcmp(cmd, "exit\n") == 0)        {            break;        }    }    return 0;}


ЗАКЛЮЧЕНИЕ
Ядро exsc осуществляет только низкий уровень взоимодействия с клиентами. Хоть это и самый важный элемент серверной системы, основа на которой всё строится, помимо него нужно строить более верхние уровни, которые будут отвечать за управление подключений, генерирование сообщений, сборку сообщений (которые вероятно будут приходить за несколько этапов). Если статья будет иметь положительный отклик то я напишу вторую чать, в которой разовью тему более верхнего уровня этой библиотеки написанной с использованием Qt, а именно про класс ExServer.

Ссылка на библиотеку github.com/extenup/exnetwork

Пример расположен в архиве exsc_test_0.zip
Источник: habr.com
К списку статей
Опубликовано: 06.03.2021 22:12:47
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

C++

Qt

Серверная оптимизация

Сетевые технологии

C

Network programming

Server

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru