Этот баннер — требование Роскомнадзора для исполнения 152 ФЗ.
«На сайте осуществляется обработка файлов cookie, необходимых для работы сайта, а также для анализа использования сайта и улучшения предоставляемых сервисов с использованием метрической программы Яндекс.Метрика. Продолжая использовать сайт, вы даёте согласие с использованием данных технологий».
Политика конфиденциальности
|
|
|
Как асинхронно отправлять данные в TCP максимально быстро на каналах любой скорости?
|
|||
|---|---|---|---|
|
#18+
Задача: Надо асинхронно отправить сообщение (например 3 мб) в TCP сокет максимально быстро. Отправка идет блоками фиксированного размера. Должно максимально быстро работать как по гигабиту в локалке, так и через GPRS в GSM-свистках. Отправка идет через сервер-посредник, который максимально забирает и кэширует принятое и доставляет получателю. Т.е. реально что могут идти в перемешку блоки сообщений от нескольких отправителей. Тут есть проблема быстрого отправителя и медленного получателя, но считаем кэш сервера безграничным. Никаких настроек/галочек/параметров извне о скорости соединения быть не должно. Чистый автомат подстраивающийся под канал. С приемом проблем нет, считаем что он идальный и супербыстрый (постоянный select() на чтение). Из найденного для ускорения: важен размер блока 17396723 стоит только начать давать за раз на байт больше чем MTU, так сразу фрагментация замедляет передачу. Особенно заметно на быстром канале. 100 мбит падает до 50-60 если давать блок данных чуть больше. Например если MTU 1500, даешь 1461 байт данных + 40 заголовки TCP и IP т.е. пакет 1501 - тормозит. Это порешано. C синхронной отправкой все просто и замечательно: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. Т.е. забивает буфер отправки до отказа, висит на send() пока не освободится место и снова забивает, как все забъет ждет ответ. Прием ответов не рассматриваем, там проблем нет. Порвалось соединение до получения ответа - считаем что не дошло. Все чудесно. Идеально. Никакого лишнего трафика и лишней нагрузки на проц. Но синхронно. То же самое асинхронно: Тупо висеть нельзя, идет отправка нескольких сообщений в разные сокеты, если один буфер забит - надо перейти к следующему, т.е. отправка схематично так Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. Во избежание недопониманий: примеры образные, т.е. просьба понимающих не придираться к static int i и #define, непонимающим - тупо не копипастить (чтобы потом не писать что работает только один раз). С виду почти тоже самое, вызывай асинхронно while(send_async()); почаще и будет счастье. Реально проблемы: 1. Вызывать слишком часто - при отправке в медленное соединение буфер не освободился, бесполезная нагрузка на процессор. Вызываю раз в 20 мс. 2. Вызывать слишком редко - при отправке в быстрое соединение простои в отправке. 20 мс очень много для гигабита. Пока так порешал: в первом пакете отправки (т.е. каждого вызова while(send_async());) добавляется флаг запроса подтверждения приема, по приходу ответа пауза прекращается и снова добивается буфер до полного. Тут на гигабите пауз ноль, скорость по максимуму, но на медленном канале буфер добивается по одному пакету, что приводит к отправке потверждения каждого пакета получателем, что забивает ненужным трафиком и так очень медленный канал. Можно увеличить буфер отправки и отказаться от подтверждений, но надо сильно увеличить, по описанной методе с подтверждением хватает 50 кб чтобы выжать максимум из гигабита, если не подтверждать, то чтобы буфер не пустел надо минимум 2,5 мбайта (1000 мбит / 8 / 1000 * 20 мс), т.е. с гарантированным запасом 3-4 мбайт. Много. Особенно если надо обслуживать много сокетов при небольшом количестве оперативки. 1000 сокетов = 3-4 Гб оперативки. Потом не практично: вдруг завтра попадется канал 10-100 гигабит, тормозить будет. Предлолагаемые пути поиска решения: 1. Автоувеличение буфера для быстрых соединений, но как определить что его не хватает? Классика многоуровневой отправки говорит что верхний уровень не должен знать что делает нижний, т.е. сунул на отправку - считай ушло, не лезет - сунь позже. 2. Минимизировать количество подтверждений? Можно просить следующее после получения предыдущего. Соединение надежное, ничего не теряется. В медленном соединении будут редко, в быстром - часто, да и пофиг, оно быстрое. Вроде должно заработать, не проверял, придумал пока писал (правильно говорят - хочешь что-то понять попробуй объяснить другому). 3. Создавать кучу потоков чтобы одновременно синхронно отправлять несколько сообщений в несколько сокетов. Можно пул потоков, но вдруг 100500 сообщений надо будет отправить одновременно, несколько медленных остановят кучу быстрых. Потом остановка этого пула не простое занятие. Плюс дополнительные проблемы с синхронизацией. Может кто-то что еще предложит? Я пока за вариант 2, не тестил, но вроде должно взлететь. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.03.2015, 21:43 |
|
||
|
Как асинхронно отправлять данные в TCP максимально быстро на каналах любой скорости?
|
|||
|---|---|---|---|
|
#18+
Еще вопрос про контроль обрыва соединения. Не дошел до этой темы. Как понимаю пока идет отправка из буфера, TCP обнаружит обрыв соединения и сообщит ошибкой в select() ожидающий прием. но если буфер весь отправлен, то реально ничего не ходит и отправитель не поймет что получатель отпал при попытке отправить подтверждение приема. Будет тупо ждать пока что-нибудь не пошлет? Правильно понимаю или там сложнее все? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.03.2015, 22:11 |
|
||
|
Как асинхронно отправлять данные в TCP максимально быстро на каналах любой скорости?
|
|||
|---|---|---|---|
|
#18+
Dima T, 1) Вызывать send (логический) до получения события готовности от сокета неверно. Асинхронность немного не так применяется. Вот есть буферы данных готовые к отправке каждый в свой сокет. Отправляете первые пакеты в каждый сокет. Вызваете select для всех сокетов одним вызовом. select вернет те сокеты которые готовы к дальнейшей отправке. Отправляете по ним следующую порцию и снова вызываете select для всех сокетов с неотправленными буферами. И так пока остаются данные в буферах. 2) Есть 2 варианта обрыва соединения 1) одна из сторон закрыла сокет (явно или неявно, например при падении программы) 2) произошел физический обрыв В первом случае, другая сторона при попытке читать или писать в сокет получит ошибку (eof, write error). Во втором случае, ошибка не сразу обнаруживается. Точнее при чтении она вообще не обнаруживается, а при записи TCP сначала пытается в несколько попыток передать пакеты и только потом выдает ошибку broken pipe. Эти попытки происходят в течении от нескольких секунд до минут (я точно не помню). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.03.2015, 22:42 |
|
||
|
Как асинхронно отправлять данные в TCP максимально быстро на каналах любой скорости?
|
|||
|---|---|---|---|
|
#18+
Коряво второй пример нарисовал, сильно упростил надо так Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 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. и вызов по тексту упоминается while(send_async()) читать как if(!send_async()) Модераторы, поправьте пожалуйста. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.03.2015, 23:15 |
|
||
|
Как асинхронно отправлять данные в TCP максимально быстро на каналах любой скорости?
|
|||
|---|---|---|---|
|
#18+
Запость корректный исходник. А предыдущий мы удалим. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.03.2015, 23:21 |
|
||
|
Как асинхронно отправлять данные в TCP максимально быстро на каналах любой скорости?
|
|||
|---|---|---|---|
|
#18+
Anatoly Moskovsky1) Вызывать send (логический) до получения события готовности от сокета неверно. Асинхронность немного не так применяется. Вот есть буферы данных готовые к отправке каждый в свой сокет. Отправляете первые пакеты в каждый сокет. Вызваете select для всех сокетов одним вызовом. select вернет те сокеты которые готовы к дальнейшей отправке. Отправляете по ним следующую порцию и снова вызываете select для всех сокетов с неотправленными буферами. И так пока остаются данные в буферах. Понял, логично, буду думать. У меня все заточено на UDP, отправил и забыл, поток select()`ом ответы слушает, а тут второй поток надо для отправки. Ломать придется всю схему :( Anatoly Moskovsky2) Есть 2 варианта обрыва соединения 1) одна из сторон закрыла сокет (явно или неявно, например при падении программы) 2) произошел физический обрыв В первом случае, другая сторона при попытке читать или писать в сокет получит ошибку (eof, write error). Во втором случае, ошибка не сразу обнаруживается. Точнее при чтении она вообще не обнаруживается, а при записи TCP сначала пытается в несколько попыток передать пакеты и только потом выдает ошибку broken pipe. Эти попытки происходят в течении от нескольких секунд до минут (я точно не помню). Закрытие второй стороной норамально отрабатывается, я про второй случай писал, тоже думать надо, тупо ждать ответа не вариант. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.03.2015, 23:28 |
|
||
|
Как асинхронно отправлять данные в TCP максимально быстро на каналах любой скорости?
|
|||
|---|---|---|---|
|
#18+
maytonЗапость корректный исходник. А предыдущий мы удалим. под спойлером 17407528 второй пример заменить ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.03.2015, 23:30 |
|
||
|
Как асинхронно отправлять данные в TCP максимально быстро на каналах любой скорости?
|
|||
|---|---|---|---|
|
#18+
Dima TЗакрытие второй стороной норамально отрабатывается, я про второй случай писал, тоже думать надо, тупо ждать ответа не вариант. У select и его аналогов есть таймаут если что. Определитесь сколько вы готовы ждать и по таймауту закрывайте сокеты и пробуйте переподключиться. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2015, 00:16 |
|
||
|
Как асинхронно отправлять данные в TCP максимально быстро на каналах любой скорости?
|
|||
|---|---|---|---|
|
#18+
Anatoly Moskovsky1) Вызывать send (логический) до получения события готовности от сокета неверно. Я сначала select() вызываю с нулевым таймаутом. Если сокет свободен вызываю send() (функция my_send() в примере) Anatoly MoskovskyАсинхронность немного не так применяется. Вот есть буферы данных готовые к отправке каждый в свой сокет. Отправляете первые пакеты в каждый сокет. Вызваете select для всех сокетов одним вызовом. select вернет те сокеты которые готовы к дальнейшей отправке... Вот этого знания мне и не хватало, как использовать select(), сам додумался только для одного сокета. Переварил. Все отлично вписалось в мою схему с незначительными доработками. Не хватало callback-вызова для пробуждения отправки. Упрощенная схема скрещивания UDP и TCP Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 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. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. Все взято с действующей схемы, кроме добавки с пробуждением, которую еще не делал. Сейчас буду вживлять :) Anatoly MoskovskyDima TЗакрытие второй стороной норамально отрабатывается, я про второй случай писал, тоже думать надо, тупо ждать ответа не вариант. У select и его аналогов есть таймаут если что. Определитесь сколько вы готовы ждать и по таймауту закрывайте сокеты и пробуйте переподключиться. Тут проблемка: соединения два Отправитель->Сервер->Получатель. Критичен обрыв Сервер->Получатель, причем сервер понятия нее имеет должен ли быть ответ или нет. В принципе Получатель получит обрыв при отправке, переустановит соединение и пошлет ответ. Отправителю можно тупо ждать и по таймауту считать что не дошло. Как вариант сервер переспросить жив ли Получатель. В целом понял как работает, буду изобретать. Спасибо за разъяснения. PS mayton, не надо ничего менять, пусть будет как есть, какая-то фигня у меня получилась и не рабочий код и для схематичного показа сложновато. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2015, 09:12 |
|
||
|
Как асинхронно отправлять данные в TCP максимально быстро на каналах любой скорости?
|
|||
|---|---|---|---|
|
#18+
ОК ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2015, 09:25 |
|
||
|
Как асинхронно отправлять данные в TCP максимально быстро на каналах любой скорости?
|
|||
|---|---|---|---|
|
#18+
Все заработало. select() одновременно слушает входящие и сигналит о возможности слать исходящие. Код: plaintext 1. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2015, 16:12 |
|
||
|
Как асинхронно отправлять данные в TCP максимально быстро на каналах любой скорости?
|
|||
|---|---|---|---|
|
#18+
Dima TВсе заработало. select() одновременно слушает входящие и сигналит о возможности придётся изучить ещё epoll, kqueue, если до винды дойдёт - completion port ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.03.2015, 19:02 |
|
||
|
Как асинхронно отправлять данные в TCP максимально быстро на каналах любой скорости?
|
|||
|---|---|---|---|
|
#18+
ИзопропилDima TВсе заработало. select() одновременно слушает входящие и сигналит о возможности придётся изучить ещё epoll, kqueue, если до винды дойдёт - completion port Это лишнее. select() в линуксе и виндовсе одинаково работает. TCP в инете ускорять бесполезно: замеры показывают что его ужимают как хостинги так и оконечные провайдеры 17406919 . ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.03.2015, 19:19 |
|
||
|
Как асинхронно отправлять данные в TCP максимально быстро на каналах любой скорости?
|
|||
|---|---|---|---|
|
#18+
Dima TЭто лишнее. select() в линуксе и виндовсе одинаково работает. различается серьёзно объём данных передаваемый между ядром и процессом твой сервис не два же соединения собирается обрабатывать? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.03.2015, 20:28 |
|
||
|
Как асинхронно отправлять данные в TCP максимально быстро на каналах любой скорости?
|
|||
|---|---|---|---|
|
#18+
Изопропилтвой сервис не два же соединения собирается обрабатывать? Побольше. Но какого-то одного перегруженного узла не ожидается. В идеале клиенты меж собой общаются, сервера для помощи в случаях когда невозможно напрямую, количество серверов можно наращивать. Искусственный тест перегрузки одного клиента проведу - будет видно запас прочности, может и потребуется изучить альтернативы select()`у под виндой, но пока это излишняя преждевременная оптимизация. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.03.2015, 07:48 |
|
||
|
Как асинхронно отправлять данные в TCP максимально быстро на каналах любой скорости?
|
|||
|---|---|---|---|
|
#18+
Dima T, На клиенте можно и select. Не думаю что у вас там будут десятки тысяч одновременных соединений. А вот на сервере, который всех этих клиентов обслуживает, select будет тормозить. Вообще я бы на вашем месте взял бы boost.asio и не морочил бы голову такими деталями. Тем более что в последних версиях там появилась поддержка асинхронности на основе coroutine которая настолько упрощает асинхронный код, превращая его по форме в синхронный, что не использовать ее - грех )) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.03.2015, 07:55 |
|
||
|
Как асинхронно отправлять данные в TCP максимально быстро на каналах любой скорости?
|
|||
|---|---|---|---|
|
#18+
Anatoly MoskovskyНа клиенте можно и select. Не думаю что у вас там будут десятки тысяч одновременных соединений. А вот на сервере, который всех этих клиентов обслуживает, select будет тормозить. До сотни одновременных обращений на одного клиента может быть. Клиент у меня и сервер и клиент в обычном понимании, а мой сервер по сути просто шлюз который их соединяет. Если в понятиях классической трехзвенки рассуждать, то один мой клиент это сервер приложения, второй к нему обращается. Все за НАТами сидят, для того и нужен шлюз. Поэтому либо они по UDP напрямую пообщаются (предварительные тесты показали что 70-80% трафика так пойдет), либо через шлюз, который просто пересылает инфу из одного соединения во второе. Anatoly MoskovskyВообще я бы на вашем месте взял бы boost.asio и не морочил бы голову такими деталями. В принципе просто интересно покопаться для общего развития. Узнал много нового и интересного. boost.asio уже попробовал, оно для меня более замороченное оказалось, там кучу других деталей надо осваивать. Не большой знаток С++. Если бы дальше на С++ планировал что-то писать, тогда имело бы смысл поизучать. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.03.2015, 15:31 |
|
||
|
Как асинхронно отправлять данные в TCP максимально быстро на каналах любой скорости?
|
|||
|---|---|---|---|
|
#18+
Dima T, дима. Ты select/epoll знаешь? Принципы. Юзкейс. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 27.01.2016, 21:37 |
|
||
|
Как асинхронно отправлять данные в TCP максимально быстро на каналах любой скорости?
|
|||
|---|---|---|---|
|
#18+
maytonDima T, дима. Ты select/epoll знаешь? Принципы. Юзкейс. select освоил, остальное неуниверсально, epoll в виндовсе нет. Что хочешь получить? Для TCP лучше либу какую-нибудь взять готовую: libevent() или boost::asio. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 27.01.2016, 21:51 |
|
||
|
Как асинхронно отправлять данные в TCP максимально быстро на каналах любой скорости?
|
|||
|---|---|---|---|
|
#18+
Я TCP так и не добавил, точнее попытался и бросил. Накопилось столько доделок, в т.ч. фундаментальных, что пишу с нуля версию 2.0. Внутренняя логика в корне изменилась. Что там будет с TCP пока не решил, может велосипед с select(), может либу возьму, скорее всего либа на сервере и велосипед на клиенте, не знаю, однозначно TCP будет для ущербных клиентов, для нормальных UDP. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 27.01.2016, 22:14 |
|
||
|
Как асинхронно отправлять данные в TCP максимально быстро на каналах любой скорости?
|
|||
|---|---|---|---|
|
#18+
Dima T, ты мне нужен чел как консультант по networks. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 27.01.2016, 22:21 |
|
||
|
Как асинхронно отправлять данные в TCP максимально быстро на каналах любой скорости?
|
|||
|---|---|---|---|
|
#18+
Читани мой последний тяпничный топик. И стукнись в этот документ https://docs.google.com/document/d/1skhNFFu_ZL-hjCi9ANQTEtz_VKBuJhrMGzUGfJBR8Yc/edit возможно потребуются привилегии. Я выдам. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 27.01.2016, 22:27 |
|
||
|
Как асинхронно отправлять данные в TCP максимально быстро на каналах любой скорости?
|
|||
|---|---|---|---|
|
#18+
maytonDima T, ты мне нужен чел как консультант по networks. Не считаю себя гуру в этом вопросе. Кое-что знаю. Чем могу - помогу. Спрашивай. Есть мысли выложить свою поделку в опенсорц, только нужны ли кому-то результаты моих измышлений? Если кому-то интересно - откликнитесь, вынесу в сторону специфику (шифрование) остальное выложу, если кому-то поможет мое псевдо P2P - буду рад. Если кто-то захочет поучаствовать - буду рад вдвойне. Читал про торрентовские поделки пришел к выводу что там дела не лучше чем мои задумки. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 27.01.2016, 22:30 |
|
||
|
Как асинхронно отправлять данные в TCP максимально быстро на каналах любой скорости?
|
|||
|---|---|---|---|
|
#18+
Anatoly Moskovsky, а еще если tcp keepalive большой стоит, то ой как не скоро поймешь, что сокет оборван. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.01.2016, 11:16 |
|
||
|
Как асинхронно отправлять данные в TCP максимально быстро на каналах любой скорости?
|
|||
|---|---|---|---|
|
#18+
Dima TЕсли кому-то интересно - откликнитесь, вынесу в сторону специфику (шифрование) остальное выложу, если кому-то поможет мое псевдо P2P - буду рад. Если кто-то захочет поучаствовать - буду рад вдвойне. Читал про торрентовские поделки пришел к выводу что там дела не лучше чем мои задумки. У меня также существует проблема с клиентами за NAT. очень интересно посмотреть реализацию обхода через шлюз. Если лицензия будет позволять интегрировать твой код в другую OpenSource программу, выкладывай на github свой движок. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.01.2016, 10:47 |
|
||
|
|

start [/forum/topic.php?fid=57&fpage=38&tid=2018623]: |
0ms |
get settings: |
8ms |
get forum list: |
12ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
47ms |
get topic data: |
15ms |
get forum data: |
2ms |
get page messages: |
88ms |
get tp. blocked users: |
2ms |
| others: | 324ms |
| total: | 506ms |

| 0 / 0 |
