Russian Qt Forum
Ноябрь 24, 2024, 21:10 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: tcp proxy server. Только на berkley sockets (select/poll/epoll)  (Прочитано 11931 раз)
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« : Январь 30, 2024, 14:45 »

Доброго времени суток, коллеги!)

На собеседовании дали тестовое задание разработать Tcp proxy server для Postgresql с возможностью логирования
всех SQL запросов, проходящих через него.
При этом нужно использовать Berkley sockets (select/poll/epoll). Прочих зависимостей быть не должно.
Прокси должен уметь обрабатывать большое количество соединений без создания потока
(thread) на каждое соединение. Необходимо распарсить сетевые пакеты, проходящие через
прокси, в которых содержатся SQL запросы, извлечь эти запросы из пакетов и записать их
в файл в виде текста (по одному запросу в строке, структура неважна). И т.д..

Тема для меня совсем новая, раньше сетевым программированием не занимался.
Поэтому пришлось убить все выходные на расскуривание данного вопроса.

Своял код (проект прилагаю). При реализации из select/poll/epoll   выбор пал на poll.
Если кому не сложно и кто в теме, покритикуйте пожалуйста.
Может как то по элегантнее можно реализовать. Боюсь, у меня уже взгляд замыленный..  Улыбающийся

Заранее спасибо)


Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #1 : Январь 30, 2024, 17:04 »

С сетью работал оочень давно). Похоже, что должно работать.

Цитировать
Необходимо распарсить сетевые пакеты, проходящие через
прокси, в которых содержатся SQL запросы, извлечь эти запросы из пакетов и записать их
в файл в виде текста (по одному запросу в строке, структура неважна)

Вот этой части не нашел. В обработчике только вывод в cout.

По идее SQL запросы необходимо собирать из сетевых пакетов.
При этом пакеты могут неожиданно разрываться и слипаться между собой.
Должен быть какой-то признак окончания запроса (м.б. символ";").
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #2 : Январь 30, 2024, 17:39 »

Цитировать
Вот этой части не нашел. В обработчике только вывод в cout.
Да, спасибо за замечание) Парсинг запросов я пока не делал. Этим будет заниматься
Код
C++ (Qt)
data_handler
 
в методе run:
Код
C++ (Qt)
void run(std::ostream & logger, const received_data_handler_t & data_handler);
 
В ТЗ сказано:
Цитировать
Необходимо распарсить сетевые пакеты, проходящие через
прокси, в которых содержатся SQL запросы, извлечь эти запросы из пакетов и записать их
в файл в виде текста (по одному запросу в строке, структура неважна).

По идее SQL запросы необходимо собирать из сетевых пакетов.
При этом пакеты могут неожиданно разрываться и слипаться между собой.
Должен быть какой-то признак окончания запроса (м.б. символ";").
Вот. Займусь как раз этим вопросом) Эта тема для меня тоже пока новая  Улыбающийся

Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #3 : Январь 30, 2024, 18:47 »

Так а проксик то работает? Улыбающийся
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #4 : Январь 30, 2024, 19:11 »

Так а проксик то работает? Улыбающийся
Ну я у себя запускал, работает) Но на большом числе клиентов не тестировал)
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
qate
Супер
******
Offline Offline

Сообщений: 1177


Просмотр профиля
« Ответ #5 : Январь 30, 2024, 23:15 »

а почему m_remote_sd один ? если я правильно понял задачу - будет, например 10 клиентов к прокси, которая сделает 10 коннектов к БД
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #6 : Январь 30, 2024, 23:46 »

а почему m_remote_sd один ? если я правильно понял задачу - будет, например 10 клиентов к прокси, которая сделает 10 коннектов к БД

А одного m_remote_sd для этого достаточно. Прокси последовательно перебирает всех активных клиентов (событие POLLIN), читает данные от каждого, обрабатывает и пробрасывает  их на remote_server (через сокет m_remote_sd)
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
qate
Супер
******
Offline Offline

Сообщений: 1177


Просмотр профиля
« Ответ #7 : Январь 31, 2024, 00:53 »

а как сервер через прокси ответит нужному клиенту (о выполнении запроса) если он не знает кому ?
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #8 : Январь 31, 2024, 08:17 »

а как сервер через прокси ответит нужному клиенту (о выполнении запроса) если он не знает кому ?

Ну по логике, сервер и не должен ничего знать о том, какой клиент отправил запрос. Его задача получить запрос, обработать и отправить ответ.
Всю консолидацию данных между сервером и клиентами берёт на себя прокси.
Сейчас сделано (возможно топорно) так:
У прокси есть список активных клиентов. Он последовательно перебирает их, читает у каждого запрос, обрабатывает его и шлёт дальше на удалённый сервер. Дожидается ответа и шлёт ответ клиенту. Затем переходит к следующему в списке клиенту и т.д..
Здесь (в моей реализации), я подозреваю, есть слабое место: прокси должен дождаться ответа от сервера, прежде чем перекинуть серверу следующего клиента..
Здесь меня это смущает, конечно Улыбающийся    
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #9 : Январь 31, 2024, 08:49 »

Как я понимаю, сейчас прокси может обрабатывать один запрос от одного клиента. Только после завершения обмена с одним клиентом, происходит переход к следующему.
Но это не очень эффективно, если мы отправили серверу запрос, который он будет обрабатывать 5 секунд, а от других клиентов есть запросы, которые сервер сможет выполнить параллельно за 1 сек, то из-за прокси клиенты будут ждать, пока выполниться долгий запрос.
Т.е. все запросы выполняются последовательно, а тот же postgres может их обрабатывать параллельно.

Логика должна быть другой, на старте поднимается только сокет, который принимает подключения от клиентов.
При подключении нового клиента, выполняем подключение к серверу и после этого имеем пару сокетов client-proxy и proxy-server, вот все что приходит по первому сокету, нужно отправить во второй и наоборот. Если один из сокетов закрывается, то нужно закрыть и второй.
Как правило эти два сокета храняться в объектах, которые называют session. Улыбающийся
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #10 : Январь 31, 2024, 09:14 »

Логика должна быть другой, на старте поднимается только сокет, который принимает подключения от клиентов.
При подключении нового клиента, выполняем подключение к серверу и после этого имеем пару сокетов client-proxy и proxy-server, вот все что приходит по первому сокету, нужно отправить во второй и наоборот. Если один из сокетов закрывается, то нужно закрыть и второй.
Как правило эти два сокета храняться в объектах, которые называют session. Улыбающийся
Согласен) 
По сути, m_remote_sd должен быть слушающим. Запускать poll и ждать событий POLLOUT от удалённого сервера..
Переделаю сегодня. Спасибо)
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
qate
Супер
******
Offline Offline

Сообщений: 1177


Просмотр профиля
« Ответ #11 : Январь 31, 2024, 09:34 »

Дожидается ответа и шлёт ответ клиенту

теперь ясно )

а как решается проблема, что трафик между клиентом, например psql, и сервером - это не plain text и вычленить sql запросы не очевидно как ?
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #12 : Январь 31, 2024, 09:51 »

Дожидается ответа и шлёт ответ клиенту

теперь ясно )

а как решается проблема, что трафик между клиентом, например psql, и сервером - это не plain text и вычленить sql запросы не очевидно как ?

Я пока предполагаю, что это просто plain text в котором могут быть sql запросы.
Сейчас реализовано так:
Код
C++ (Qt)
proxy.run(std::cout, [&](const std::string & data)
       {
           auto query_list = sandbox::get_sql_query(data);
           for (const auto & query : query_list)
               out << query << std::endl;
       });
 
где парсер просто извлекает из текста запросы:
Код
C++ (Qt)
#ifndef SQL_PARSER_H
#define SQL_PARSER_H
 
#include <regex>
#include <string>
#include <list>
 
namespace sandbox {
 
inline std::list<std::string> get_sql_query(const std::string & src)
{
   std::regex query_regex("(SELECT[^;]+;)");
 
   auto query_begin = std::sregex_iterator(src.begin(), src.end(), query_regex);
   auto query_end = std::sregex_iterator();
 
   std::regex r("\\n");
 
   std::list<std::string> result;
 
   for (std::sregex_iterator i = query_begin; i != query_end; ++i)
   {
       std::smatch match = *i;
 
       result.push_back(std::regex_replace(match.str(), r, " "));
   }
 
   return result;
}
 
} /* namespace sandbox */
 
#endif // SQL_PARSER_H
 
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #13 : Январь 31, 2024, 10:26 »

А если запрос получен не полностью?
Например, получили только
"SELECT * FRO"
а остаток прилетит позже?
Записан
qate
Супер
******
Offline Offline

Сообщений: 1177


Просмотр профиля
« Ответ #14 : Январь 31, 2024, 10:30 »

Я пока предполагаю, что это просто plain text в котором могут быть sql запросы.

не похоже https://www.manniwood.com/2016_12_29/tcpdump_pg.html
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.27 секунд. Запросов: 22.