Модераторы: feodorv

Поиск:

Закрытая темаСоздание новой темы Создание опроса
> Почему не нужно использовать BSD-sockets?! а ведь и правда - не нужно! 
:(
    Опции темы
boostcoder
Дата 16.8.2011, 23:01 (ссылка) |    (голосов:4) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 13
Всего: 110



не понимаю я резона возиться с "этим"(BSD-sockets)! и не понимаю, что заставляет других использовать "это"! 1) отсутствие с++ компилятора? - это вряд ли, 2) не знание английского на столько, что даже доку по какому-то фреймворку/библиотеке(POCO, boost.asio, Qt) прочесть невозможно? - тоже маловероятно. 3) не знание с++? - тоже маловероятно.
так в чем же причина?! - возможно в том, что многие даже не задумываются о том что существуют альтернативы? - а вот это возможно!
а альтернативы есть, уверяю! и одна из них зовется asio.

фух... высказался...


итак. что же вам даст asio?
1. абстрагирование от платформы/ОС.
2. большое кол-во поддерживаемых платформ/ОС:
  • Linux Kernel 2.4
  • Linux Kernel 2.6
  • Solaris
  • QNX Neutrino
  • Mac OS X
  • FreeBSD
  • AIX
  • HP-UX
  • Tru64
  • Windows 95, 98, Me, NT, 2000, XP, 2003, Vista, Win7
3. высокую расширяемость, как в плане написания своих _всячески_специализированных_ оберток поверх asio, так и заложенные в основу asio такие "турбонаддуватели" как custom_memory_allocation и invocation_strategy, и, при правильном проектировании вашего кода, возможность выполнять всю работу в указанном вами кол-ве потоков без использования примитивов синхронизации и "ручного" распределения запросов по рабочим потокам!
вы только вдумайтесь в каждый из перечисленных пунктов: 
3.1. custom_memory_allocation - позволяет вам использовать собственный аллокатор для повышения скорости запросов на выделение памяти, и одновременно, полностью избежать фрагментации памяти! задумайтесь: boost::bind(который вы будите использовать почти везде при использовании asio) при создании функционального объекта выполняет new, а при разрушении - delete. а добавьте к этому аллоцирование буферов для операций чтения/записи, и это уже не мелочь! это здоровый кусок процессорного времени, тратится на не очевидные на первый взгляд действия.
3.2. invocation_strategy - при использовании custom_memory_allocation, позволяет производить вызов функциональных объектов, уже созданных ранее, и лежащих в аллокаторе! в добавок, invocation_strategy, при использовании вашим кодом нескольких рабочих потоков, полностью избавляет вас от необходимости разграничения доступа к общим ресурсам! т.е. никаких мьютексов!
4. очень удобную модель основанную на патернах Reactor и Proactor.


одумайтесь!
пожалуйста, не пишите больше "такой" код.

спасибо.


зы
даже не думал кого-то обидеть/задеть/оскорбить.

зызы
дописывать примеры буду в топик. следите.




1. Основы
1.1. io_service:
Основа любой программы использующей asio - io_service. Это означает, что Вы не можете создать объект сокета/аксептора не имея объекта io_service`а.
Код

#include <boost/asio.hpp>

int main() {
   boost::asio::io_service ios;

   boost::asio::ip::tcp::acceptor acceptor(ios);
   boost::asio::ip::tcp::socket socket(ios);
}


io_service::run()
Если Вы используете только блокирующие операции, такие как acceptor::accept() или socket::receive()/socket::send()/read()/write(), то Вам вовсе не нужно вызывать io_service::run(). Иначе, читаем далее...
Способы и правила вызова io_service::run()
Бессмысленно вызывать io_service::run() раньше чем Вы создали хотя бы одну задачу. Т.е., задача - это результат создания любой асинхронной операции(не путать с _результат_выполнения_). Так, к примеру, async_read() создает задачу, которая будет выполняться до тех пор, пока не будет прочтено требуемое кол-во байт, или, пока не произойдет ошибка.
Код

#include <boost/asio.hpp>

void handler(
  const boost::system::error_code& error, // Result of operation.

  std::size_t bytes_transferred           // Number of bytes copied into the
                                          // buffers. If an error occurred,
                                          // this will be the  number of
                                          // bytes successfully transferred
                                          // prior to the error.
)
{
   // ...
}

int main() {
   boost::asio::io_service ios;
   
   boost::asio::ip::tcp::socket socket(ios);
   
   char buff[1024];
   boost::asio::async_read(socket, boost::asio::buffer(buff), &handler);
   
   ios.run(); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
}

В этом примере, мы, при помощи async_read(), создаем _задачу_асинхронного_чтения_, и только после этого, вызываем io_service::run(). Иначе, если вызов io_service::run() и async_read() поменять местами, то наша программа завершится не успев начаться smile

Если же у Вас высокопроизводительный сервер, то, возможно, Вы столкнетесь с тем, что Вам будет недостаточно одного рабочего потока. И Вы, как и любой порядочный программист, начнете изменять архитектуру для того, чтоб распределять задачи между несколькими рабочими потоками(трэды, очереди ,и т.д...). НЕ ДЕЛАЙТЕ ЭТОГО! В asio, это уже сделано за Вас.
Немного изменяем предыдущий пример так:
Код

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>

void handler(
  const boost::system::error_code& error, // Result of operation.

  std::size_t bytes_transferred           // Number of bytes copied into the
                                          // buffers. If an error occurred,
                                          // this will be the  number of
                                          // bytes successfully transferred
                                          // prior to the error.
)
{
   // ...
}

int main() {
   boost::asio::io_service ios;
   
   boost::asio::ip::tcp::socket socket(ios);
   
   char buff[1024];
   boost::asio::async_read(socket, boost::asio::buffer(buff), &handler);
   
   const size_t threads_count = 4; // нам необходимы четыре рабочих потока
   boost::thread_group threads;
   for ( size_t idx = 0; idx < threads_count; ++idx ) {
      threads.create_thread(
         boost::bind(&boost::asio::io_service::run, boost::ref(ios))
      );
   }

   threads.join_all();
}


Все! Теперь asio распределяет задачи между четырьмя рабочими потоками.
Но в этом примере есть один не очевидный(на первый взгляд) подвох: когда закончатся задачи, io_service::run() вернет управление, и, как следствие, завершатся все рабочие потоки. И любая асинхронная операция более никогда не выполнится.
Чтоб такого не произошло, изменяем пример следующим образом:
Код

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>

void handler(
  const boost::system::error_code& error, // Result of operation.

  std::size_t bytes_transferred           // Number of bytes copied into the
                                          // buffers. If an error occurred,
                                          // this will be the  number of
                                          // bytes successfully transferred
                                          // prior to the error.
)
{
   // ...
}

int main() {
   boost::asio::io_service ios;
   boost::shared_ptr<boost::asio::io_service::work> work(
      new boost::asio::io_service::work(ios)
   ); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   
   boost::asio::ip::tcp::socket socket(ios);
   
   char buff[1024];
   boost::asio::async_read(socket, boost::asio::buffer(buff), &handler);
   
   const size_t threads_count = 4; // нам необходимы четыре рабочих потока
   boost::thread_group threads;
   for ( size_t idx = 0; idx < threads_count; ++idx ) {
      threads.create_thread(
         boost::bind(&boost::asio::io_service::run, boost::ref(ios))
      );
   }
   
   threads.join_all();
}

http://liveworkspace.org/code/167382d82712...ed4bf8905cca716
Теперь, вне зависимости от кол-ва задач, объект io_service`а будет продолжать работать и ожидать поступления новых задач. Для этого, мы создали объект типа io_service::work. Почему объект io_service::work мы храним в смарт_поинтере? - потому что это дает нам возможность удалить его вызовом "work.reset()" для того чтоб завершить рабочие потоки и программу.

1.2. Буферы
Скорее всего, вам это никогда не пригодится. Можете смело пропускать этот раздел smile 

Заглядывая в документацию по таким функциям/методам как socket::receive()/socket::send()/read()/write(), вы будите видеть типы параметров буферов, к примеру, MutableBufferSequenceConstBufferSequence. Что же означают эти типы, и какие к ним требования? Все просто.
Давайте рассмотрим требования к типу MutableBufferSequence.
В требованиях говорится про:
value_type - который должен быть синонимом T.
const_iterator - тип итератора, соответствующего требованиям bidirectional-итератора(Bidirectional iterator requirements).
const_iterator begin(); - метод, возвращающий итератор указывающий на первый элемент.
const_iterator end(); - метод, возвращающий итератор указывающий на последний элемент.

ConstBufferSequence Имеет такие же требования, за исключением спецификаторов константности.

1.3. Время жизни буферов

1.4. Completion-handlers

...в процессе...

Это сообщение отредактировал(а) boostcoder - 13.10.2011, 13:45
PM WWW   Вверх
serghd
Дата 16.8.2011, 23:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 136
Регистрация: 5.10.2009

Репутация: нет
Всего: нет



Про custom_memory_allocation наслышан, да. В высоконагруженных системах самое оно.
Пример invocation_strategy при использовании custom_memory_allocation если имеется, пожалуйста. Особенно интересен вызов функторов, лежащих в аллокаторе.

Это сообщение отредактировал(а) serghd - 16.8.2011, 23:30
PM MAIL   Вверх
boostcoder
Дата 16.8.2011, 23:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 13
Всего: 110



Цитата(serghd @  16.8.2011,  23:27 Найти цитируемый пост)
Пример invocation_strategy при использовании custom_memory_allocation если имеется, пожалуйста.

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

Это сообщение отредактировал(а) boostcoder - 17.8.2011, 08:20
PM WWW   Вверх
Sahab
Дата 16.8.2011, 23:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 151
Регистрация: 1.9.2009

Репутация: нет
Всего: 3



А Вы не думали сударь, что иногда бывает навязана стратегия реализации проекта. Например, использовать только бздишные сокеты?
PM MAIL   Вверх
boostcoder
Дата 16.8.2011, 23:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 13
Всего: 110



Цитата(Sahab @  16.8.2011,  23:33 Найти цитируемый пост)
А Вы не думали сударь

это страшно.
тем, кто находится в таком "положении" - строго настрого игнорить тему, дабы не разочаровываться ;)
PM WWW   Вверх
serghd
Дата 24.8.2011, 20:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 136
Регистрация: 5.10.2009

Репутация: нет
Всего: нет



Код

#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>

void handler
(
 const boost::system::error_code& error, // Result of operation.
 
 std::size_t bytes_transferred           // Number of bytes copied into the
                                         // buffers. If an error occurred,
                                         // this will be the  number of
                                         // bytes successfully transferred
                                         // prior to the error.
) { std::cout << "txt" << std::endl; }

int main() 
{
 boost::asio::io_service ios;
   boost::shared_ptr<boost::asio::io_service::work> work(
      new boost::asio::io_service::work(ios)
   );
   
 boost::asio::ip::tcp::socket socket(ios);

 char buff[1024];
 boost::asio::async_read(socket, boost::asio::buffer(buff), &handler);

 const size_t threads_count = 4; // нам необходимы четыре рабочих потока
 boost::thread_group threads;
 for ( size_t idx = 0; idx < threads_count; ++idx ) 
 {
  threads.create_thread(
   boost::bind(&boost::asio::io_service::run, boost::ref(ios))
  );
 }
 threads.join_all(); // <<<<<<<<< ждём завершения всех потоков
}

http://liveworkspace.org/code/6baaa4952219...db32b0b3f9af140
Вопрос, наверное, ламерский, но тем не менее. Почему текст выводится один, а не 4 раза?smile
Т.е. я понимаю, что после первого вывода ios должен возвратить управление. Но чтобы он работал дальше, мы используем work. Тогда в чём подвох?


Это сообщение отредактировал(а) serghd - 24.8.2011, 21:33
PM MAIL   Вверх
boostcoder
Дата 25.8.2011, 14:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 13
Всего: 110



async_read() создает одну задачу. и выполняется одна задача.
ты ведь не задачу создаешь четыре раза, а рабочие потоки.
PM WWW   Вверх
serghd
Дата 25.8.2011, 18:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 136
Регистрация: 5.10.2009

Репутация: нет
Всего: нет



просто думал, что каждый поток вызывает свой async_read() (т.е. все они используют при этом один и тот же ios). Но если нет, значит нет)

Это сообщение отредактировал(а) serghd - 25.8.2011, 19:28
PM MAIL   Вверх
Леопольд
Дата 9.9.2011, 13:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 943
Регистрация: 17.6.2009

Репутация: нет
Всего: 13



Цитата(boostcoder @  16.8.2011,  23:01 Найти цитируемый пост)
Если же у Вас высокопроизводительный сервер, то, возможно, Вы столкнетесь с тем, что Вам будет недостаточно одного рабочего потока. И Вы, как и любой порядочный программист, начнете изменять архитектуру для того, чтоб распределять задачи между несколькими рабочими потоками(трэды, очереди ,и т.д...). НЕ ДЕЛАЙТЕ ЭТОГО! В asio, это уже сделано за Вас.
Немного изменяем предыдущий пример так:
А что если вылетит исключение в потоке?


Это сообщение отредактировал(а) Леопольд - 9.9.2011, 13:34


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
boostcoder
Дата 9.9.2011, 13:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 13
Всего: 110



Цитата(Леопольд @  9.9.2011,  13:20 Найти цитируемый пост)
А что если вылетит исключение в потоке?

обрабатываете его в том же потоке, и, в зависимости от типа исключения, либо продолжаете работать, либо валите приложение.

Добавлено через 1 минуту и 53 секунды
ибо при возникновении исключения в любом и элементов очереди io_service, из очереди будет выброшен только этот элемент. поэтому этот же io_service спокойно может продолжить работать. иначе вообще, ничего бы не могло в asio работать нормально, при таком раскладе smile
PM WWW   Вверх
Леопольд
Дата 9.9.2011, 13:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 943
Регистрация: 17.6.2009

Репутация: нет
Всего: 13



Цитата(boostcoder @  9.9.2011,  13:23 Найти цитируемый пост)
обрабатываете его в том же потоке
Т.е. во всех хендлерах, где может быть исключение, нужны try/catch?


Это сообщение отредактировал(а) Леопольд - 9.9.2011, 13:36


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
newbee
Дата 9.9.2011, 13:42 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бревно
**


Профиль
Группа: Участник
Сообщений: 703
Регистрация: 24.8.2011

Репутация: нет
Всего: 19



А где можно посмотреть непредвзятое сравнение высоконагруженного многопользовательского сервера на этом азио и линуксовом сишном epoll? Можно с распределением на равное число потоков или процессов. Интересует скорость реакции и число обработанных запрросов в единицу времени.


--------------------
You're face to face
With man who sold the world
PM   Вверх
boostcoder
Дата 9.9.2011, 13:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 13
Всего: 110



Цитата(Леопольд @  9.9.2011,  13:36 Найти цитируемый пост)
Т.е. во всех хендлерах, где может быть исключение, нужны try/catch?

нет. try-catch нужно только в точке вызова io_service::run()

PM WWW   Вверх
boostcoder
Дата 9.9.2011, 14:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 13
Всего: 110



Цитата(newbee @  9.9.2011,  13:42 Найти цитируемый пост)
на этом азио и линуксовом сишном epoll?

asio в лине и использует epoll.

PM WWW   Вверх
newbee
Дата 9.9.2011, 14:46 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бревно
**


Профиль
Группа: Участник
Сообщений: 703
Регистрация: 24.8.2011

Репутация: нет
Всего: 19



Цитата(boostcoder @  9.9.2011,  15:42 Найти цитируемый пост)

asio в лине и использует epoll.
Я в курсе. Мне интересно сравнение чистого еполла и того, что спрятан за тысячью фасадов и колбэков в азио.


--------------------
You're face to face
With man who sold the world
PM   Вверх
Закрытая темаСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Сети | Следующая тема »


 




[ Время генерации скрипта: 0.1656 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.