Название: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: m_ax от Январь 30, 2024, 14:45 Доброго времени суток, коллеги!)
На собеседовании дали тестовое задание разработать Tcp proxy server для Postgresql с возможностью логирования всех SQL запросов, проходящих через него. При этом нужно использовать Berkley sockets (select/poll/epoll). Прочих зависимостей быть не должно. Прокси должен уметь обрабатывать большое количество соединений без создания потока (thread) на каждое соединение. Необходимо распарсить сетевые пакеты, проходящие через прокси, в которых содержатся SQL запросы, извлечь эти запросы из пакетов и записать их в файл в виде текста (по одному запросу в строке, структура неважна). И т.д.. Тема для меня совсем новая, раньше сетевым программированием не занимался. Поэтому пришлось убить все выходные на расскуривание данного вопроса. Своял код (проект прилагаю). При реализации из select/poll/epoll выбор пал на poll. Если кому не сложно и кто в теме, покритикуйте пожалуйста. Может как то по элегантнее можно реализовать. Боюсь, у меня уже взгляд замыленный.. :) Заранее спасибо) Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: ssoft от Январь 30, 2024, 17:04 С сетью работал оочень давно). Похоже, что должно работать.
Цитировать Необходимо распарсить сетевые пакеты, проходящие через прокси, в которых содержатся SQL запросы, извлечь эти запросы из пакетов и записать их в файл в виде текста (по одному запросу в строке, структура неважна) Вот этой части не нашел. В обработчике только вывод в cout. По идее SQL запросы необходимо собирать из сетевых пакетов. При этом пакеты могут неожиданно разрываться и слипаться между собой. Должен быть какой-то признак окончания запроса (м.б. символ";"). Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: m_ax от Январь 30, 2024, 17:39 Цитировать Вот этой части не нашел. В обработчике только вывод в cout. Да, спасибо за замечание) Парсинг запросов я пока не делал. Этим будет заниматься Код в методе run: Код В ТЗ сказано: Цитировать Необходимо распарсить сетевые пакеты, проходящие через прокси, в которых содержатся SQL запросы, извлечь эти запросы из пакетов и записать их в файл в виде текста (по одному запросу в строке, структура неважна). По идее SQL запросы необходимо собирать из сетевых пакетов. Вот. Займусь как раз этим вопросом) Эта тема для меня тоже пока новая :)При этом пакеты могут неожиданно разрываться и слипаться между собой. Должен быть какой-то признак окончания запроса (м.б. символ";"). Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: Old от Январь 30, 2024, 18:47 Так а проксик то работает? :)
Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: m_ax от Январь 30, 2024, 19:11 Так а проксик то работает? :) Ну я у себя запускал, работает) Но на большом числе клиентов не тестировал) Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: qate от Январь 30, 2024, 23:15 а почему m_remote_sd один ? если я правильно понял задачу - будет, например 10 клиентов к прокси, которая сделает 10 коннектов к БД
Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: m_ax от Январь 30, 2024, 23:46 а почему m_remote_sd один ? если я правильно понял задачу - будет, например 10 клиентов к прокси, которая сделает 10 коннектов к БД А одного m_remote_sd для этого достаточно. Прокси последовательно перебирает всех активных клиентов (событие POLLIN), читает данные от каждого, обрабатывает и пробрасывает их на remote_server (через сокет m_remote_sd) Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: qate от Январь 31, 2024, 00:53 а как сервер через прокси ответит нужному клиенту (о выполнении запроса) если он не знает кому ?
Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: m_ax от Январь 31, 2024, 08:17 а как сервер через прокси ответит нужному клиенту (о выполнении запроса) если он не знает кому ? Ну по логике, сервер и не должен ничего знать о том, какой клиент отправил запрос. Его задача получить запрос, обработать и отправить ответ. Всю консолидацию данных между сервером и клиентами берёт на себя прокси. Сейчас сделано (возможно топорно) так: У прокси есть список активных клиентов. Он последовательно перебирает их, читает у каждого запрос, обрабатывает его и шлёт дальше на удалённый сервер. Дожидается ответа и шлёт ответ клиенту. Затем переходит к следующему в списке клиенту и т.д.. Здесь (в моей реализации), я подозреваю, есть слабое место: прокси должен дождаться ответа от сервера, прежде чем перекинуть серверу следующего клиента.. Здесь меня это смущает, конечно :) Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: Old от Январь 31, 2024, 08:49 Как я понимаю, сейчас прокси может обрабатывать один запрос от одного клиента. Только после завершения обмена с одним клиентом, происходит переход к следующему.
Но это не очень эффективно, если мы отправили серверу запрос, который он будет обрабатывать 5 секунд, а от других клиентов есть запросы, которые сервер сможет выполнить параллельно за 1 сек, то из-за прокси клиенты будут ждать, пока выполниться долгий запрос. Т.е. все запросы выполняются последовательно, а тот же postgres может их обрабатывать параллельно. Логика должна быть другой, на старте поднимается только сокет, который принимает подключения от клиентов. При подключении нового клиента, выполняем подключение к серверу и после этого имеем пару сокетов client-proxy и proxy-server, вот все что приходит по первому сокету, нужно отправить во второй и наоборот. Если один из сокетов закрывается, то нужно закрыть и второй. Как правило эти два сокета храняться в объектах, которые называют session. :) Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: m_ax от Январь 31, 2024, 09:14 Логика должна быть другой, на старте поднимается только сокет, который принимает подключения от клиентов. Согласен) При подключении нового клиента, выполняем подключение к серверу и после этого имеем пару сокетов client-proxy и proxy-server, вот все что приходит по первому сокету, нужно отправить во второй и наоборот. Если один из сокетов закрывается, то нужно закрыть и второй. Как правило эти два сокета храняться в объектах, которые называют session. :) По сути, m_remote_sd должен быть слушающим. Запускать poll и ждать событий POLLOUT от удалённого сервера.. Переделаю сегодня. Спасибо) Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: qate от Январь 31, 2024, 09:34 Дожидается ответа и шлёт ответ клиенту теперь ясно ) а как решается проблема, что трафик между клиентом, например psql, и сервером - это не plain text и вычленить sql запросы не очевидно как ? Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: m_ax от Январь 31, 2024, 09:51 Дожидается ответа и шлёт ответ клиенту теперь ясно ) а как решается проблема, что трафик между клиентом, например psql, и сервером - это не plain text и вычленить sql запросы не очевидно как ? Сейчас реализовано так: Код где парсер просто извлекает из текста запросы: Код
Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: Old от Январь 31, 2024, 10:26 А если запрос получен не полностью?
Например, получили только "SELECT * FRO" а остаток прилетит позже? Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: qate от Январь 31, 2024, 10:30 Я пока предполагаю, что это просто plain text в котором могут быть sql запросы. не похоже https://www.manniwood.com/2016_12_29/tcpdump_pg.html Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: m_ax от Январь 31, 2024, 10:41 А если запрос получен не полностью? Например, получили только "SELECT * FRO" а остаток прилетит позже? Значит нужен какой то признак того, что данные полученны не полностью/полностью.. Я читаю данные в буфер Код Как мне узнать, что ответ получен не полностью и ожидается продолжение? Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: Old от Январь 31, 2024, 10:49 Прочитал очередную порцию данный (chunk) добавил к общему буферу.
А дальше уже смотришь, если в общем буфере получена команда полностью (от SELECT и до ';'), то выкусываем ее из буфера и обрабатываем, иначе ждем оочередной чанк. Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: qate от Январь 31, 2024, 10:50 Как мне узнать, что ответ получен не полностью и ожидается продолжение? никак - tcp потоковый протокол для этих целей делают логический пакет "[размер][данные]" Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: m_ax от Январь 31, 2024, 10:55 Прочитал очередную порцию данный (chunk) добавил к общему буферу. А дальше уже смотришь, если в общем буфере получена команда полностью (от SELECT и до ';'), то выкусываем ее из буфера и обрабатываем, иначе ждем оочередной чанк. никак - tcp потоковый протокол для этих целей делают логический пакет "[размер][данные]" Понятно) Спасибо) сегодня будет чем заняться) Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: ssoft от Январь 31, 2024, 10:58 При подключении нового клиента, выполняем подключение к серверу и после этого имеем пару сокетов client-proxy и proxy-server, вот все что приходит по первому сокету, нужно отправить во второй и наоборот. Если один из сокетов закрывается, то нужно закрыть и второй. Как правило эти два сокета хранятся в объектах, которые называют session. :) Я тоже к такой схеме пришёл). Назвал объект только proxy_client. Цитировать Как мне узнать, что ответ получен не полностью и ожидается продолжение? Нужно реальный трафик смотреть. В общем случае никак. Если в сети текст, то надеяться, что есть разделитель ";", либо по слову "SELECT" или другим косвенным признакам. Если бинарный протокол, то его нужно знать, скорее всего, где-то длина пакета должна быть. Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: Old от Январь 31, 2024, 11:00 И еще момент, лучше разделять запросы по ';' не смотря на 'SELECT'.
В SQL есть и другие команды, кроме выборки данных (SELECT). :) Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: ssoft от Январь 31, 2024, 11:10 И еще момент, лучше разделять запросы по ';' не смотря на 'SELECT'. В SQL есть и другие команды, кроме выборки данных (SELECT). :) По хорошему да.., но ';' не обязателен в конце запроса. Поэтому про пример трафика и пишу. Если явных признаков начала и конца нет, то парсер придется писать)). Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: Old от Январь 31, 2024, 11:22 Посмотрел трафик postgresql, там бинарный формат, но очень простой.
Код
type = 0x51 - Simple query length содержит длину тела, включая само поле length payload содержит строку запроса 'select * from tab;' type = 0x54 - Row description Это ответ на запрос, row идут последовательно один за другим Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: qate от Январь 31, 2024, 11:27 Посмотрел трафик postgresql, там бинарный формат, но очень простой. еще в помощь https://dev.to/yugabyte/how-to-sniff-postgresql-traffic-3idm и все это надо сделать как тестовое задание ? ) Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: m_ax от Январь 31, 2024, 13:38 Цитировать и все это надо сделать как тестовое задание ? ) Ну да) Вот полный текст :) Цитировать Разработать на C++ TCP прокси-сервер для СУБД Postgresql с возможностью логирования всех SQL запросов, проходящих через него. Документация по сетевому протоколу этой СУБД доступна на официальном сайте. Для выполнения тестового задания нужно использовать Berkley sockets (select/poll/epoll). Прочих зависимостей быть не должно. Прокси должен уметь обрабатывать большое количество соединений без создания потока (thread) на каждое соединение. Необходимо распарсить сетевые пакеты, проходящие через прокси, в которых содержатся SQL запросы, извлечь эти запросы из пакетов и записать их в файл в виде текста (по одному запросу в строке, структура неважна). Для того, чтобы в прокси были видны SQL запросы в незашифрованном виде, необходимо отключить SSL (на клиенте и/или сервере). Должна присутствовать минимальная обработка ошибок, так же желательны комментарии в тех местах, где возможны ошибки. Приложение не должно падать на нескольких десятках одновременных соединений, выполняющих запросы к СУБД без перерыва в течение 5 минут (можно использовать sysbench для тестирования). Операционная система Linux, компилятор – GCC, так же необходимо создать файл для сборки проекта с помощью cmake или make. Цель выполнения тестового задания – проверка профессиональных навыков кандидатов на вакантную позицию. Написанный Вами код не будет использоваться в продуктах компании или передан третьим лицам. Результат выполнения тестового задания можно выложить на github.com под любой лицензией во избежание использования Вашего кода. Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: sergek от Январь 31, 2024, 16:18 А если запрос получен не полностью? А в конце - точка с запятойНапример, получили только "SELECT * FRO" а остаток прилетит позже? Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: m_ax от Февраль 03, 2024, 16:42 Всем спасибо за консультацию и советы)
Всё вроде более-менее поправил. Отправил им на рассмотрение :) Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: Old от Февраль 04, 2024, 20:31 Результатов пока нет? :)
Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: m_ax от Февраль 04, 2024, 20:49 Результатов пока нет? :) Пока нет) Завтра, наверное, озвучат) Но, пожалуй, я в любом случае откажусь, поскольку пока это тестовое задание писал, прошёл другое собеседование. Показал им свои проекты, там сразу взяли) Завтра пойду оформляться :) Название: Re: tcp proxy server. Только на berkley sockets (select/poll/epoll) Отправлено: m_ax от Февраль 06, 2024, 16:24 Результатов пока нет? :) Ваше тестовое задание просмотрели, оценили как очень хороший результат. Как следствие, хотели бы пригласить вас на собеседование. :) |