- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
void worker(int id)
{
while (true) {
std::unique_lock<std::mutex> lock(connPoolMutex);
connPoolCond.wait(lock, [] { return !connectionsPool.empty(); });
ClientConnection conn = connectionsPool.front();
connectionsPool.pop();
lock.unlock();
TCPSocket sock(conn);
sock.setReadTimeout(READ_TIMEOUT);
char buffer[MAX_PACKET_LEN] = {};
int sz = sock.recv(buffer, sizeof(buffer));
// [...]
}
}
// [...]
int main()
{
// [...]
TCPSocket server("0.0.0.0:1234");
server.bind();
server.listen(1000);
while (true) {
ClientConnection conn = server.accept();
std::unique_lock<std::mutex> l(connPoolMutex);
connectionsPool.push(conn);
connPoolCond.notify_one();
}
}
bagor 17.08.2016 08:29 # +7
CHayT 17.08.2016 09:42 # +15
> захардкожено
-2
guesto 17.08.2016 10:21 # +7
CHayT 17.08.2016 10:24 # +15
guesto 17.08.2016 10:28 # +6
Dummy00001 17.08.2016 11:47 # +16
а вот слушание на 0.0.0.0 часто попадает в продакшн, и вот тот самопальный тестовый сокет сервер резко становится доступным почти всем пользователям интернета. (если я не ошибаюсь это был один из элементов с которых SCADA security фиаско и началось. Сименс это относительно быстро пофиксил, но было уже поздно потому что хацкеры уже начали глубже копать. и просто убирание INADDR_ANY, после того как осознали потенциал, что покойнику припарка.)
guesto 17.08.2016 13:41 # +8
man iptables
Dummy00001 17.08.2016 13:48 # +20
вместо что бы тупой баг пофиксить - давайте фаервол сделаем обязательным.
guesto 17.08.2016 13:51 # +7
но на самом деле я согласен: серверов без настрйоки IP адреса не бывает в природе
это наколенная поделка
Dummy00001 17.08.2016 13:56 # +18
сомневаюсь.
на самом деле в интернет такое подключается редко, и это больше нужно как локальная секурити фича, что бы локальные пользователи не могли чего-то случайно/преднамерено сделать.
CHayT 17.08.2016 13:52 # +16
guesto 17.08.2016 14:10 # +9
неправильно так говорить
настраивают netfilter, а iptables это просто клиентская тулза
3_14dar 17.08.2016 16:45 # +6
guesto 17.08.2016 16:47 # +9
3_14dar 17.08.2016 17:06 # +9
3_14dar 17.08.2016 16:46 # +9
Dummy00001 17.08.2016 16:57 # +15
насколько я помню там говно было на многих уровнях, включая то что Сименская обслуживающая софтина через фаервол и доступится не могла к девайсам - она требовала что бы девайсы были в той же сети. софтина стоит на ПЦ, ПЦ стоит в корпоративной сете == девайсы стоят в корпоративной сети. тушите свет.
3_14dar 17.08.2016 17:07 # +7
guesto 17.08.2016 17:09 # +6
ого, как всё запущено) Информатику в школе прогуливал?
3_14dar 17.08.2016 17:11 # +5
В лужу бзданул. Теперь выпутывайся.
Dummy00001 17.08.2016 17:18 # +16
3_14dar 17.08.2016 17:20 # +6
>она требовала что бы девайсы были в той же сети.
В том же широковещательном домене?
Dummy00001 17.08.2016 17:34 # +39
Железо/софт слали/принимали слегка кривые пакеты, которые фаерволы дропают, потому что они кривые.
> В том же широковещательном домене?
Подробностей не видел.
3_14dar 17.08.2016 18:00 # −7
CHayT 17.08.2016 11:49 # +14
kurwa 17.08.2016 11:52 # +5
gost 17.08.2016 12:30 # +16
Таким образом, если все обрабатывающие потоки будут заняты обработкой запроса, новые соединения будут игнорироваться, причём не до тех пор, пока какой-то поток освободится, а ещё и до тех пор, пока не придут другие соединения.
kurwa 17.08.2016 12:43 # +6
В общем-то в этом коде написан классический producer-consumer. Можешь запомнить этот паттерн - пригодится.
gost 17.08.2016 13:26 # +13
Это не условие как таковое, это защита от ложных пробуждений, т.е. connPoolCond.wait(pred) эквивалентно
(http://en.cppreference.com/w/cpp/thread/condition_variable/wait).
Поэтому, когда какой-то поток закончит с обработкой запроса, он просто уйдёт в спячку, поскольку очередной notify_one() был проигнорирован всеми.
Dummy00001 17.08.2016 13:52 # +16
PS я крестовой версией еще не пользовался, но сомневаюсь что они от pthread_cond_wait() (с которого это API сдиралось) далеко отклонились.
kurwa-nextgen 17.08.2016 14:42 # +15
roman-kashitsyn 18.08.2016 11:07 # +36
Ты сам не понял тот код, который выложил, gost.
gost 18.08.2016 12:44 # +38
Всё ещё хуже: я не понял код, который сам и написал...
kurwa 17.08.2016 12:45 # +4
kurwa-nextgen 17.08.2016 14:50 # +16
Вот еще до этого тезиса доебусь. На этом "кривом решении" основано дохуя серверов даже сейчас. Люди начали использовать тредпул с общей очередью запросов, когда догадались, что не обязательно спавнить тред/форкаться на каждый запрос. И это был основной подход в серверах до тех пор, пока не случилось c10k и не стали актуальны всякие еполлы.
Dummy00001 17.08.2016 15:20 # +13
когда я последний раз (на перле!) делал тупой форк сервер, пока он еще был в зачаточной форме (буквально - accept + fork) я попробовал найти лимит соединений в секунду. но обломался. потому что как выяснилось все тестовые проги которые были под рукой (включая глючную версию нетката) были еще большее тормозными. на как минимум 1к в секунду на процессор/коре можно с легкостью полагаться. с глючными тестовыми прогами я доходил до 1.5к соединений в секунду - но судя по нагрузке системной, можно было бы лоад в 4-5 раз еще поднять. еще раз: тупой форк сервак на перле.
kurwa 18.08.2016 09:28 # −22
Dummy00001 18.08.2016 11:14 # +34
это работает (очень) хорошо только в том случае если у тебя сервак в запросе делает не много и делает в гарантировано фиксированое время. но если тебе надо на диск или в базу ходить, тогда зеленые потоки могут (и по личному опыту: будут) подсасывать.
как по мне, все языки которые сокеты/этц предоставляют, должны просто включать в стандартную библиотеку полноценную реализацию сокет сервака. в случае С/С++, есть кучи мелких граблей - но в случае managed языков с GC, большинства этих проблем нет, и я не вижу причин почему нет. (хотя исторический пример жабы, где все через Ж шло, не вдохновляет.)
roman-kashitsyn 18.08.2016 11:28 # +36
Чем это объясняется? Чем доступ к базе из зелёного потока принципиально отличается от доступа из обычного потока, при условии правильной реализации клиента?
Dummy00001 18.08.2016 12:10 # +35
зеленые потоки реализуют preemption перекрывая потенциально-блокирующие сисколлы врапперами. в враперах либо стартуется асинхронная версия, либо ставится какой таймер для периодического опроса, либо хез чего еще.
не все сисколлы легко перекрыть (например: специальная семантика с обработкой сигналов или restartable логика какая есть. или просто повторно вызывать нельзя.)
но самая главная проблема это то что они не могут знать сколько долго системный вызов будет блокировать - и будет ли он вообще блокировать.
в тривиальном случае, если зеленые потоки глупо будут исходить из того что системный вызов всегда блокирует, это будет приводить к серьёзной потере производительности из-за излишнего скедулинга. (в прошлом я такое видел как 100% CPU load на простом сетевом пинг-понге (echo server))
поэтому зеленые потоки пытаются жульничать: от предварительно полла на файл/сокет дескриптере (не на всех дескрипторах/не всегда работает), до каких hi-res таймеров (сливает потенциальные проблемы в кернел, и кернелы это не любят и могут приоритет задачи снизить/грануларити повысить). это все эвристики, которые временами лажаются, и временами ухудшают производительность. (я в прошлом был в ситуации когда поток просыпался с задержкой 10-25мс потому что тайминг складывался такой что либа делала полл на мой сокет 1-2мс до прихода данных, и прикладуха спокойно спала до следующего тика внутреннего таймера.)
это как бы и была главная причина почему народ в 90х массивно пытался с зеленых потоков на нативные переходить :-)
roman-kashitsyn 18.08.2016 13:01 # +35
Чем принципиально отличается лапша из коллбэков и таймеров, которую ты напишешь на еполле/бусть.ио от аналогичной лапши, но генирируемой автоматически из простых прямолинейных исходников?
Dummy00001 18.08.2016 13:35 # +34
> автоматически из простых прямолинейных исходников?
(а) Где?
(б) Никакая автоматика не способна догадаться на 100% что именно в исходниках происходит, и как именно оно на практике должно работать.
> лапша из коллбэков и таймеров, которую ты напишешь на еполле/бусть.ио
В этой лапше разраб явно описывает семантику того что будет происходить и как на это надо реагировать.
... Я может пропустил там какие-то передовые технологии в этом вашем Go. Теоретически, на уровне языка можно больше интересного сделать в этом направлении. Практически, это не помогает, потому что чем больше ты отдаляешь код от нативного интерфейса, тем больше потенциальных граблей создаешь.
roman-kashitsyn 18.08.2016 15:07 # +34
Ну вот в бусте ты говоришь что-то вроде "прочитай из вот этого сокета N байт и вызови вот эту функцию, когда закончишь".
Чем это отличается от рантайма, который суспендит зелёный тред на "блокирующем" вызове, сам создаёт нужный обработчик асинхронного вызова и будит тред обратно, когда данные пришли? Где тут возможность использовать "дополнительную" семантику?
Dummy00001 18.08.2016 15:15 # +34
Наконец таки. Возвращаемся к тому что я написал ранее: И как твой рантайм догадывается что вызов "блокирующий"?
В программе с бустом, просто факт что использую буст.асио явно говорит что я ожидаю что вызов будет блокироватся.
В абсрактной программе, "socket.recv()" может значить кучу различных вещей. Включая что я ожидаю прочитать 0 байт, ака EOF. И даже это может блокировать. (Блин, даже "socket.close()" может блокировать.)
roman-kashitsyn 18.08.2016 15:26 # +35
Очевидно, стандартная библиотека поставляется вместе с рантаймом, и он тупо знает, какие вызовы блокирующие (в том смысле, что ждут что-то от внешних устройств), а какие -- нет. В том смысле, что всё взаимодействие с внешним миром уже завёрнуто в правильные усыпляющие обёртки.
Есть определённый хардкорчик с FFI, но это всегда отдельная песня.
Dummy00001 18.08.2016 15:35 # +34
расскажи мне когда блокируют recv()/read(). (теже яйца на виндах, только с другой стороны: опросить можно все, но опросы не сильно торопливые (включая загадочные случаи где WaitSingleObject(0ms) медленнее чем ReadFile()).)
roman-kashitsyn 18.08.2016 15:41 # +35
Стандартная библиотека содержит ровно столько магии, сколько в неё положили.
> расскажи мне когда блокируют recv()/read()
Расскажи лучше, как прочитать из сокета с таймаутом в юниксе.
Dummy00001 18.08.2016 15:54 # +34
libev/libevent/libuv или чего там нынче актуально - и они это делают за тебя. или даже тот же QSocketNotifier.
на живом POSIX это делается - poll()'ом с POLLIN флагом. `pollfd pfd; pfd.fd = sockDes; pfd.events = POLLIN; rc = poll( &pfd, 1, timeOutMillis )`. если poll() вернул 0 - то таймаут. если 1 - то можно читать гарантировано без блокировки.
те библиотеки (и тот же QSocketNotifier) это просто оболочки для главного цикла приложения вокруг poll() вызова, которые автоматизируют за тебя работу с массивом pollfd структур (или структур/этц для других API типа epoll).
roman-kashitsyn 18.08.2016 15:58 # +36
Вот к этому я и вёл: в посиксе ты даже таймаут на чтение/запись выставить без полла не сможешь, поэтому доводы типа "блокирующий быстрее, полл тормозит" как-то не очень убедительно смотрятся.
guesto 18.08.2016 16:04 # −136
обычно или epoll или kqueue, нет?
Dummy00001 18.08.2016 16:19 # +35
знаю что смешно выглядит, но это как раз часто что происходит в реальной жизни: чтение не будет блокировать если уже есть данные. поэтому излишние поллы будут только тормозить. (и блин это как раз то на чем часто спотыкаются: в тесте все ожидания ждут; а в продакшене данные валят и валят, ожидания не случаются и логика программы едет/события происходят в неожиданный момент времени.)
с другой стороны случай на который я выше ссылался это как раз то что происходит в зеленых потоках: ОС знает о событии, но так как нет потока/задачи/процесса (ОС объекта) который заблокирован на ожидании этого события, ОС ничего с этим событием (кроме как поставить в очередь) сделать не может. событие проморгал - не заметишь его до тех пор пока активно еще раз ОС про события не спросишь.
guesto 18.08.2016 16:35 # −30
Иной раз блокировки происходят так редко и на такой маленький срок что люди вообще делают спин-лок. Правда это в ядре
Dummy00001 18.08.2016 16:51 # +34
спинлоки тут даже рядом не валялись - они не совместимы с ожиданием событий.
и в ядре эта тематика - ожидания событий - выглядит на изнанку. пришел пакет, подняли прерывание, достали данные из буфера, разбудили IP стэку что есть работа, IP стэк проснулся и переложил данные TCP стэку и его разбудили, TCP стэк проснулся, мапнул данные на соединение/сокет, сложил данные данные в буфер сокета, и когда кончил, (если есть epoll) положил/обновил сообщение в очереди событий, разбудил приложени(е,я) которые ждут.
тут как раз с романом спор то и идет. он склоняется/предпочитает к простой последовательной обработке данных (почему хотят потоки). в юзерспэйс это работает - тут можно делать что угодно. в то время как в кернел спэйс все безжалостно event-driven, и альтернатив никаких нет.
guesto 18.08.2016 16:57 # −30
внешних событий -- да, потому что с точки зрения ядра могут пройти многие годы, прежде чем придет пакет
Я имел ввиду что способ зависит от частоты прихода данных
guest6 10.01.2024 22:18 # 0
Я, впринципе, согласен, что неблокирующий вызов это жертвование латенси в пользу пропускания. В котлиновских корутинах ktor, например, неблокирубщее чтение сосет в 10 раз у блокирующего сокета
Dummy00001 18.08.2016 12:36 # +35
цель это не избегать нативных потоков. цель это их полноценно загружать работой.
лучший вариант это когда стандартная либа просто реализует какой гибкий IO мультиплексинг, который позволяет приложению работать с произвольным количеством нативных потоков. к этому как правило сводятся все такого типа приложения. например boost.asio.
kurwa-nextgen 18.08.2016 16:42 # +35
Если бы кто запилил в буст нормальные файберы с примитивами синхронизации и ио, я бы пользовался.
Dummy00001 18.08.2016 16:54 # +35
но если тебе нужно работать асинхронно с файлами - то альтернатив мало (я по крайней мере других не знаю).
с другой стороны, если речь идёт только про сокеты, то там все проще и есть тучи библиотек которые это делают (libev/libuv/libevent/Qt и все остальное с "main loop" в названии).
kurwa 18.08.2016 22:37 # −30
HaskellGovno 18.08.2016 22:44 # +15
guesto 18.08.2016 22:47 # −76
что не так с epoll?
а) ты типа про виндовфый FILE_FLAG_OVERLAPPED?
kurwa 18.08.2016 22:51 # −91
HaskellGovno 18.08.2016 22:53 # +15
Прошу заметить, синхронно! А это днище царя гороха. Упоротоши-красноглазики! Дма уже как в восмидесятых завезли.
Вон 8ка-10ка свои асинхронные апи запилила на все, и это я не говорю о древнем аверлапед ио
guesto 18.08.2016 22:57 # −91
Конечно же контроллер диска читает в память блоками сам.
Илиты думаешь там процесссор по 8 байтиков MOVает?
HaskellGovno 18.08.2016 22:59 # +14
Ну и нахуй тогда тебе системный поток для этого, если ПДП все стянет с диска и просигнализирует прерыванием разбудить зеленый поток? Нахрен тебе синхронность для чтения файлов? А тупые посиксные линуксоиды, одержимые кампиляцией ведра не осилили, зато ходят довольные с красными глазами
guesto 18.08.2016 23:04 # −90
я что-ль так сделал?
https://bugzilla.kernel.org/show_bug.cgi?id=15272
guesto 18.08.2016 22:59 # −91
Dummy00001 18.08.2016 22:56 # +14
http://stackoverflow.com/questions/378515/whats-the-deal-with-boost-asio-and-file-i-o
AOI на юнихах используется на столько редко что шансов у него выйти из ниши очень мало.
хороший источних примеров должен быть libtorrent - http://blog.libtorrent.org/2012/10/asynchronous-disk-io/
Dummy00001 17.08.2016 11:52 # +12
ЗЫ с вероятностью 90% говна тут нет. а последние 10% это такой редкий случай. с другой стороны, это совместимо с убогими выньсокетами.
kurwa-nextgen 17.08.2016 16:30 # +34
guesto 18.08.2016 13:07 # −140
LispGovno 18.08.2016 13:19 # +34
Главное чтоб с зелеными потоками была интеграция у ио
void_main 18.08.2016 15:42 # +241
Потоки, не загрязняющие естественную среду?
guesto 18.08.2016 15:44 # −138
а ты пиши на дельфях дальше, не отвлекай людей от серьеных бесед
void_main 18.08.2016 15:46 # +234
laMer007 18.08.2016 17:22 # +535
void_main 18.08.2016 17:37 # +264
HaskellGovno 18.08.2016 22:49 # +15
> Нет. Вручную регал, когда-то давно.
Лол. Для тебя пару дней назад (в соседнем треде рассказывал)- это когда-то давно? Ведь точно регал 139 ботов, чтоб разрушить империю говнокода, но потом стал п ушистым и хорошим
Ух щит, уже 152 бота...
void_main 18.08.2016 22:52 # +6
Не стал. Я так и остался ебанутым существом троллем и спамером.
На сайте vbbook, где я когда-то обитал, модератором был толстый, пухлый мальчик. Он очень запаривался со мной и однажды, запарившись со мной бороться, сказал с горечью : "Тролль так и останется троллем..."
HaskellGovno 18.08.2016 23:14 # +15
> Не стал. Я так и остался ебанутым существом троллем и спамером.
Это типа признание сейчас было?)
Типа регал 139 ботов, чтоб разрушить империю говнокода, но потом так и не стал пушистым и хорошим. Остался спамером? Тогда кто из твоих ботов продолжает спамить? Имя бота?
https://www.youtube.com/watch?v=PLTosCqkh70
void_main 18.08.2016 23:23 # +3
https://www.youtube.com/watch?v=WoXeh5SbHn0
смотреть с 32:48
guest 19.08.2016 14:14 # −41
guest 19.08.2016 14:31 # −40
gost 19.08.2016 14:46 # +14
void_main 19.08.2016 14:54 # −14
Ты не картвел часом?
gost 19.08.2016 14:58 # +14
guest 19.08.2016 15:00 # −48