Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

«Boost.Asio C Network Programming». Глава 1: Приступая к работе с Boost.Asio

Anna | 24.06.2014 | нет комментариев

Это мой 1-й пост, следственно не судите сурово. Я хочу начать свободный перевод книги John Torjo «Boost.Asio C Network Programming» вот ссылка на нее.

Оглавление:

  • Глава 1: Приступая к работе с Boost.Asio
  • Глава 2: Основы Boost.Asio
  • Глава 3: Echo Сервер/Клиент
  • Глава 4: Заказчик и Сервер
  • Глава 5: Синхронное вопреки асинхронного
  • Глава 6: Boost.Asio – другие особенности
  • Глава 7: Boost.Asio – добавочные темы


Во-первых разберем что есть Boost.Asio, как его собрать, а так же несколько примеров. Вы узнаете, что Boost.Asio огромнее, чем сетевая библиотека. Так же вы узнаете о самом значимом классе, тот, что находится в самом сердце Boost.Asio — io_service.

Что такое Boost.Asio?

Если коротко, Boost.Asio это, большей частью, кросс-платформенная С библиотека для программирования сетей и некоторых других низкоуровневых программ ввода/вывода.
Есть много реализаций для решения сетевых задач, но Boost.Asio превзошел их все; он был принят в Boost в 2005 и с тех пор был протестирован огромным числом пользователей Boost, применяется во многих планах, таких как:

  • Remobo , разрешает вам создавать собственную IPN
  • libtorrent , является библиотекой, которая реализует Bittorrent заказчик
  • PokerTH , представляет собой игру в покер с помощью LAN и Internet

Boost.Asio удачно абстрагирует представления input и output, которые работают не только для работы в сети, но и для последовательных COM-портов, файлов и так дальше. Помимо этого вы можете делать input либо output программирование синхронным либо асинхронным:

read(stream, buffer [, extra options]) 
async_read(stream, buffer [, extra options], handler)
write(stream, buffer [, extra options])
async_write(stream, buffer [, extra options], handler)

Как вы поспели подметить в предыдущем фрагменте кода функции принимают экземпляр потока, которым может быть что желательно (не только сокет, мы можем читать и писать в него).
Библиотека является переносимой, работает на большинстве операционных систем и отлично масштабируется при больше чем тысяче одновременных подключений. Сетевая часть была сторонником BSD(Berkeley Software Distribution) сокетов. Предоставляется API для работы с TCP (Transmission Control Protocol) сокетами, UDP (User Datagram Protocol) сокетами, IMCP(Internet Control Message Protocol) сокетами, так же библиотека является расширяемой, так, если вы хотите, то можете адаптировать ее на свой личный протокол.

История

Boost.Asio была принята в Boost 1.35 в декабре 2005г, позже начала разработки в 2003г. Изначально автором является Кристофер Кохлхофф (Christopher M. Kohlhoff), с ним дозволено связаться по адресу chris@kohlhoff.com.
Библиотека была протестирована на следующих платформах и компиляторах:

  • 32-bit и 64-bit Windows, применяя Visual C 7.1 и выше
  • Windows, с применением MinGW
  • Windows, применяя Cygwin (удостоверитесь, что определен __USE_232_SOCKETS)
  • Linux на основе ядер 2.4 и 2.6, применяя g 3.3 и выше
  • Solaris, применяя g 3.3 и выше
  • MAC OS X 10.4 , применяя g 3.3 и выше

Это также может трудиться на платформах, таких как AIX 5.3, HP-UX 11i v3, QNX Neutrino 6.3, Solaris, с применением Sun Studio 11 , True64 v5.1, Windows, с применением Borland C 5.9.2 (проконсультируйтесь наwww.boost.org для уточнения деталей).

Зависимости

Boost.Asio зависит от следующих библиотек:

  • Boost.System: эта библиотека предоставляет поддержку операционной системе для библиотеки Boost (http://www.boost.org/doc/libs/1_51_0/doc/html/boost_system/index.html)
  • Boost.Regex: эта библиотека (опция) применяется в случае, если вы используете read_until() либоasync_read_until(), которые принимают boost::regex параметр
  • Boost.DateTime: эта библиотека (опция) применяется, если вы используете таймеры Boost.Asio
  • OpenSSL: эта библиотека (опция) применяется, если вы решите применять SSL поддержку, предоставляемую Boost.Asio

Сборка Boost.Asio

Boost.Asio это чисто заголовочная библиотека. Впрочем, в зависимости от компилятора и размера вашей программы, вы можете предпочесть создание Boost.Asio как начального файла. Вы можете сделать это для уменьшения времени компиляции. Это может быть сделано следующими методами:

  • Только в одном из ваших файлов, применяя #include <boost/asio/impl/src.hpp> (если вы используете SSL, то #include <boost/asio/ssl/impl/src.hpp>)
  • Применяя #define BOOST_ASIO_SEPARATE_COMPILATION во всех ваших начальных файлах

Подметьте, что Boost.Asio зависит от Boost.System и необязательно от Boost.Regex, так что вам необходимо, по крайней мере, возвести библиотеку boost, применяя дальнейший код:

bjam –with-system –with-regex stage

Если вы так же хотите возвести тесты, то вы обязаны применять дальнейший код:

bjam –with-system –with-thread –with-date_time –with-regex –withserialization stage

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

Значимые макросы

Используйте BOOST_ASIO_DISABLE_THREADS, если установлено; он отключает поддержку потоков в Boost.Asio, самостоятельно от того был ли Boost скомпилирован с помощью потоков.

Синхронный вопреки асинхронного

Во-первых, асинхронное программирование Исключительно отличается от синхронного программирования. В синхронном программировании все операции вы делаете в последовательном порядке, такие как чтение (запрос) из сокета S, а после этого написать (результат) в сокет. Всякая из операций является блокирующей. Так как операции блокирующие, то Дабы не прерывать основную программу, в то время как вы читаете либо записываете в сокет, вы обыкновенно создаете один либо несколько потоков, которые имеют дело с сокетами ввода/вывода. Таким образом, синхронные сервер/клиенты, как правило, многопоточны.
С иной стороны, асинхронные программы управляются событиями. Вы начинаете операцию, но вы не знаете, когда она закончится; вы предоставляете callback функцию, которая будет вызываться API с итогом операции, когда операция завершится. Для программистов, которые имеют огромный навык работы с QT – кросс-платформенной библиотекой от Nokia для создания графических приложений пользовательского интерфейса, это вторая естество. Таким образом, в асинхронном программировании вам не непременно иметь огромнее, чем один поток.
Вы обязаны решить на ранней стадии вашего плана (желанно в начале) какой подход вы будете применять: синхронный либо асинхронный, так как переключение на полпути будет сложным и подвержено ошибкам; значительно отличается не только API, семантика вашей программы будет крепко изменена (асинхронные сети, как правило, сложнее для тестирования и отладки, чем синхронные). Подумайте перед тем как захотите применять либо блокирующие вызовы и много потоков (синхронная, как правило, проще) либо немного потоков и события (асинхронный, как правило, больше трудный).
Вот примитивный пример асинхронного заказчика:

using boost::asio;
io_service service;
ip::tcp::endpoint ep( ip::address::from_string("127.0.0.1"), 2001);
ip::tcp::socket sock(service);
sock.connect(ep);

Во-первых, ваша программа должна иметь экземпляр io_service. Boost.Asio использует io_service для общения с сервисом ввода/вывода операционной системы. Обыкновенно одного экземпляра io_serviceбывает довольно. Дальше сделайте адрес и порт к которому вы хотите подключиться. Сделайте сокет. Подключите сокет к вашему адресу и порту:

//Here is a simple synchronous server:using boost::asio;
typedef boost::shared_ptr<ip::tcp::socket> socket_ptr;
io_service service;
ip::tcp::endpoint ep( ip::tcp::v4(), 2001)); // listen on 2001
ip::tcp::acceptor acc(service, ep);
while ( true) 
{
    socket_ptr sock(new ip::tcp::socket(service));
    acc.accept(*sock);
    boost::thread( boost::bind(client_session, sock));
}
void client_session(socket_ptr sock)
 {
    while ( true)
     {
        char data[512];
        size_t len = sock->read_some(buffer(data));
        if ( len > 0) 
        write(*sock, buffer("ok", 2));
    }
}

Вновь же, ваша первая программа должна иметь, по крайней мере, правда бы один экземпляр io_service. После этого вы указываете порт для прослушивания и создаете акцептор (приемник) — один объект, тот, что принимает клиентские подключения.
В дальнейшем цикле вы создаете фальшивый сокет и ожидаете подключение заказчика. Позже того как соединение установлено, вы создаете поток, тот, что будет заниматься этой связью.
В потоке, в функции client_session вы слушаете запросы заказчика, интерпретируете их и отвечаете.
Для создания простого асинхронного заказчика вы будете делать что-то схожее на следующее:

using boost::asio;
io_service service;
ip::tcp::endpoint ep( ip::address::from_string("127.0.0.1"), 2001);
ip::tcp::socket sock(service);
sock.async_connect(ep, connect_handler);
service.run();
void connect_handler(const boost::system::error_code & ec)
 {
    // here we know we connected successfully
    // if ec indicates success 
}

Ваша программа должна иметь, по крайней мере один экземпляр io_service. Вы указываете где подключается и создается сокет. После этого, как только установлено соединение, вы асинхронно подключаетесь к адресу и порту (это заключение обработчика), то есть вызывается connect_handler.
Позже вызова connect_handler проверьте код на ошибки(ec), и в случае триумфа вы можете асинхронно написать серверу.
Обратите внимание, что цикл service.run() будет выполняться до тех пор пока имеются незаконченные асинхронные операции. В предыдущем примере есть только одна такая операция, это сокет async_connect. Позже этого service.run() завершается.
Всякая асинхронная операция имеет завершающий обработчик, функцию, которая будет вызвана, когда операция завершится.
Дальнейший код это легкой асинхронный сервер:

using boost::asio;
typedef boost::shared_ptr<ip::tcp::socket> socket_ptr;
io_service service;
ip::tcp::endpoint ep( ip::tcp::v4(), 2001)); // listen on 2001
ip::tcp::acceptor acc(service, ep);
socket_ptr sock(new ip::tcp::socket(service));
start_accept(sock);
service.run();
void start_accept(socket_ptr sock)
 {
    acc.async_accept(*sock, boost::bind( handle_accept, sock, _1) );
}
void handle_accept(socket_ptr sock, const boost::system::error_code & err)
 {
    if ( err) return;
    // at this point, you can read/write to the socket
    socket_ptr sock(new ip::tcp::socket(service));
    start_accept(sock);
}

В предыдущем фрагменте кода, во-первых, вы создаете экземпляр io_service. После этого вы указываете порт, тот, что будете прослушивать. Потом создаете акцептор – объект для приема клиентских подключений, а так же создаете фальшивый сокет и асинхронно ожидаете подключения заказчика.
Наконец, запускаете асинхронный цикл service.run(). При подключении заказчика вызываетсяhandle_accept (завершающий обработчик для вызова async_accept). Если нет ошибок, то вы можете применять данный сокет для операций чтения/записи.
Позже применения сокета, вы создаете новейший сокет и вновь вызываете start_accept(), которая добавляет сходственную асинхронную операцию «ожидаем подключения заказчика», оставляя циклservice.run() занятым.

Исключения вопреки кодов ошибок

Boost.Asio разрешает применять как исключения так и коды ошибок. Все синхронные функции имеют перегрузки выбрасывающие исключения в итоге ошибки либо возвращает код ошибки. Если функция падает, то она выбрасывает boost::system::system_error ошибку.

using boost::asio;
ip::tcp::endpoint ep;
ip::tcp::socket sock(service);
sock.connect(ep); // Line 1
boost::system::error_code err;
sock.connect(ep, err); // Line 2

В предыдущем коде sock.connect(ep) выбрасывает исключение в случае ошибки и sock.connect(ep, err)вернет код ошибки.
Взгляните на дальнейший фрагмент кода:

Try
 {
    sock.connect(ep);
} 
catch(boost::system::system_error e) 
{
    std::cout << e.code() << std::endl;
}

Дальнейший участок кода схож на предшествующий:

boost::system::error_code err;
sock.connect(ep, err);
if ( err)
    std::cout << err << std::endl;

В случае, если вы используете асинхронные функции, все они возвращают код ошибки, тот, что вы можете проверить в вашей функции обратного вызова. Асинхронные функции никогда не выкидывают исключений и не имеет никакого смысла делать это. А кто его поймает?
В ваших синхронных функциях вы можете применять как исключения так и коды ошибок (что огромнее захотите), но пользуйтесь чем то одним. Их смешивание может привести к загвоздкам либо даже падению (когда вы по ошибке забываете обработать исключение). Если ваш код является комплексным (вызываются функции чтения/записи в сокет), то вам, видимо, предпочтительней пользоваться исключениями и исполнять функции чтения и записи в try {} catch блоке.

void client_session(socket_ptr sock) 
{
    Try
     {
        ...
    } 
    catch ( boost::system::system_error e) 
    {
        // handle the error 
    }
}

Если вы используете коды ошибок, то вы можете отлично увидеть, когда соединение будет закрыто, как показано в дальнейшем фрагменте кода:

char data[512];
boost::system::error_code error;
size_t length = sock.read_some(buffer(data), error);
if (error == error::eof)
    return; // Connection closed

Все коды ошибок Boost.Asio находятся в пространстве имен boost::asio::error (в случае, если вы хотите сделать полный перебор для нахождения неисправности). Так же вы можете посмотретьboost/asio/error.hpp для приобретения больше подробной информации.

Потоки в Boost.Asio

Когда дело доходит до потоков в Boost.Asio, нам нужно побеседовать о дальнейшем:

  • io_service: класс io_service является потоко-неопасным. Несколько потоков могут вызватьio_service::run(). Почаще каждого вы, возможно, вызываете io_service::run() из одного потока, так что функция ожидает пока все блокирующие асинхронные функции будут исполнены. Тем не менее вы можете вызывать io_service::run() из нескольких потоков. Это блокирует все потоки, которые будут вызывать io_service::run(). Все функции обратного вызов будут вызваны в контекстах вех потоков, которые вызвали io_service::run(); это так же обозначает, что если вы вызвалиio_service::run(), только в одном потоке, то все функции обратного вызова будут вызваны в контексте данного потока.
  • socket: классы сокетов не являются потоко-неопасными. Таким образом вам следует чураться таких обстановок как читать из сокета в одном потоке, а писать в него в ином (это рекомендуется вообще, не говоря теснее о Boost.Asio).
  • utility: Классы utility обыкновенно не имеет смысла применять в нескольких потоках, они не потоко-неопасны. Множество из них применяются короткое время, а после этого выходят из области видимости.

Библиотека Boost.Asio сама по себе может применять несколько потоков помимо вашего, но гарантируется, что из этих потоков не будет вызываться ваш код. Это в свою очередь обозначает, что функции обратного вызова будут вызваны только в тех потоках, откуда вызвана io_service::run().

Не только сети

Boost.Asio в дополнение к сетям предоставляет и другие объекты ввода/вывода.
Boost.Asio разрешает применять такие сигналы как SIGTERM (закончить программу), SIGINT(прерывание сигнала), SIGSEGV (нарушение сегмента) и другие.
Вы создаете экземпляр signal_set и указываете какие сигналы ожидать асинхронно и когда один из них случится, то вызовется ваш асинхронный обработчик:

void signal_handler(const boost::system::error_code & err, int signal) 
{
    // log this, and terminate application
}
boost::asio::signal_set sig(service, SIGINT, SIGTERM);
sig.async_wait(signal_handler);

Если сгенерируется SIGINT, то вы попадете в обработчик signal_handler.
Применяя Boost.Asio, вы можете легко подключиться к ступенчатому порту. Имя порта COM7 на Windows либо /dev/ttyS0 на POSIX платформах:

io_service service;
serial_port sp(service, "COM7");

Позже открытия вы можете установить некоторые параметры, такие как скорость передачи данных порта, четность, стоп-биты, как указано в дальнейшем фрагменте кода:

serial_port::baud_rate rate(9600);
sp.set_option(rate);

Если порт открыт, то вы можете обрабатывать его в потоке, к тому же рекомендуется применять свободные функции для чтения и/или записи в ступенчатый порт, скажем, read()async_read()write(),async_write(), как показано в дальнейшем примере:

char data[512];
read(sp, buffer(data, 512));

Boost.Asio разрешает также подключаться к Windows-файлам и вновь же применять свободные функции, такие как read()asyn_read() и другие, как показано ниже:

HANDLE h = ::OpenFile(...);
windows::stream_handle sh(service, h);
char data[512];
read(h, buffer(data, 512));

Тоже самое вы можете сделать и с дескрипторами POSIX файлов, таких как пайпы, типовые I/O, разными устройствами (но не с обыкновенными файлами), как это сделано в дальнейшем фрагменте:

posix::stream_descriptor sd_in(service, ::dup(STDIN_FILENO));
char data[512];
read(sd_in, buffer(data, 512));

Таймеры

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

bool read = false;
void deadline_handler(const boost::system::error_code &) 
{
    std::cout << (read ? "read successfully" : "read failed") << std::endl;
}
void read_handler(const boost::system::error_code &) 
{
    read = true;
}
ip::tcp::socket sock(service);
…
read = false;
char data[512];
sock.async_read_some(buffer(data, 512));
deadline_timer t(service, boost::posix_time::milliseconds(100));
t.async_wait(&deadline_handler);
service.run();

В предыдущем фрагменте кода если мы читаем наши данные до окончания времени, read установлено в true, то наш компаньон достучался до нас своевременно. В отвратном случае, когда вызывается deadline_handler,read по-бывшему установлен в false, что обозначает, что мы не связались до конца отведенного времени.
Boost.Asio разрешает применять синхронные таймеры, но, обыкновенно, они равнозначны легкой операцииsleep. Строчка boost::this_thread::sleep(500); и дальнейший фрагмент сделают тоже самое:

deadline_timer t(service, boost::posix_time::milliseconds(500));
t.wait();

Класс io_service

Вы теснее видели, что огромная часть кода, которая использует Boost.Asio будет применять определенный экземпляр io_serviceio_service – самый значимый класс в библиотеке, он имеет дело с операционной системой, ожидает конца всех асинхронных операций, а потом при заключении вызывает обработчик для всякой такой операции.
Если вы решили сделать ваше приложение синхронным, то вам не необходимо волноваться о том, что я собираюсь показать в этом разделе.
Вы можете применять экземпляр io_service несколькими методами. В следующих примерах мы имеем три асинхронных операции, два объединенных сокета и таймер ожидания:

  • Один поток с одним и одним обработчиком:
    io_service service_;
    // all the socket operations are handled by service_
    ip::tcp::socket sock1(service_);
    // all the socket operations are handled by service_
    ip::tcp::socket sock2(service_);
    sock1.async_connect( ep, connect_handler);
    sock2.async_connect( ep, connect_handler);
    deadline_timer t(service_, boost::posix_time::seconds(5));
    t.async_wait(timeout_handler);
    service_.run();
    
  • Много потоков с одним экземпляром io_service и несколькими обработчиками:
    io_service service_;
    ip::tcp::socket sock1(service_);
    ip::tcp::socket sock2(service_);
    sock1.async_connect( ep, connect_handler);
    sock2.async_connect( ep, connect_handler);
    deadline_timer t(service_, boost::posix_time::seconds(5));
    t.async_wait(timeout_handler);
    for ( int i = 0; i < 5;   i)
        boost::thread( run_service);
    void run_service() 
    {
        service_.run();
    }
    
    
  • Много потоков с несколькими экземплярами io_service и несколькими обработчиками:
    io_service service_[2];
    ip::tcp::socket sock1(service_[0]);
    ip::tcp::socket sock2(service_[1]);
    sock1.async_connect( ep, connect_handler);
    sock2.async_connect( ep, connect_handler);
    deadline_timer t(service_[0], boost::posix_time::seconds(5));
    t.async_wait(timeout_handler); 
    for ( int i = 0; i < 2;   i)
        boost::thread( boost::bind(run_service, i));
    
    void run_service(int idx) 
    {
        service_[idx].run();
    }
    

Раньше каждого обратите внимание на то, что вы не можете иметь несколько экземпляров io_service в одном потоке. Не имеет смысла писать дальнейший код:

for ( int i = 0; i < 2;   i) 
    service_[i].run();

Предшествующий участок кода не имеет никакого смысла, потому что service_[1].run() затребуетservice_[0].run() при закрытии первого. Так что все асинхронные операции service_[1] обязаны будут ожидать обработки, а это не дюже отличная идея.
Во всех 3 предыдущих примерах мы ожидали три асинхронные операции для заключения. Дабы объяснить отличия, мы будем считать, что, через некоторое время, завершится операция 1 и сразу позже этого завершится операция 2. Так же мы представим, что всякому обработчику понадобится секунда, Дабы кончаться.
В первом случае мы ожидаем заключения всех 3 операций в одном потоке. Позже заключения первой операции мы вызываем ее обработчик. Даже если операция 2 завершается сразу же позже первой, мы будем обязаны ожидать секунду для вызова ее обработчика позже заключения первой операции.
Во втором случае мы ожидаем заключения 3 операций в 2-х потоках. Позже заключения первой операции мы вызываем ее обработчик в первом потоке. Как только кончаться операция 2, мы сразу же вызовем ее обработчик во втором потоке (в то время как 1-й поток занят, ждя заключения обработчика первой операции, 2-й поток может вольно ответить на заключение всякий иной операции).
В последнем случае, если операция 1 будет connect к sock1 и операция 2 connect к sock2, то приложение будет вести себя как и во втором случае. 1-й поток будет обрабатывать обработчик connect для sock1, а 2-й поток – обработчик connect для sock2. Впрочем, если из sock1 является операцией 1 и тайм-аутdeadline_timer t это операция 2, то 1-й поток будет обрабатывать обработчик для connect из sock1. Таким образом, обработчику тайм-аута deadline_timer t придется ожидать конца работы обработчика connect изsock1 (он будет ожидать одну секунду), в первом потоке обрабатывается как подключение к обработчикуsock1, так и обработчик тайм-аута t.
Вот что вы обязаны извлечь из предыдущих примеров:

  • Обстановка 1 для базовых приложений. Вы неизменно будете сталкиваться с загвоздками, если несколько обработчиков обязаны быть вызваны единовременно либо же если они обязаны будут вызываться ступенчато. Если один обработчик требует много времени для окончания, то остальным обработчикам придется подождать.
  • Обстановка 2 для большинства случаев. Это дюже отлично, если несколько обработчиков обязаны быть вызваны единовременно и всякий из них вызывается в отдельном потоке. Исключительное тесное место может появиться, если все обрабатывающие потоки заняты и в то же время обязаны быть вызваны новые обработчики. Тем не менее, в качестве простого решения дозволено легко увеличить число потоков-обработчиков.
  • Обстановка 3 является особенно трудной и больше эластичной. Вы обязаны ее применять только тогда, когда обстановки 2 неудовлетворительно. Это видимо будет допустимо, когда у вас имеется больше тысячи одновременных подключений (сокетов). Вы можете считать, что всякий поток-обработчик (поток, запустивший io_service::run()) имеет свой личный цикл select/epoll; он ожидает все сокеты, контролирует операции чтения/записи и обнаружив правда бы одну такую операцию начинает обрабатывать ее. В большинстве случаев вам не о чем волноваться, волноваться дозволено только в том случае, когда число сокетов растет экспоненциально (больше 1000 сокетов). В таком случае присутствие нескольких циклов select/epoll может увеличить время отклика.

Если вы думаете, что ваше приложение когда-нибудь перейдет к обстановки 3, то удостоверитесь, что участок кода (код, тот, что вызывает io_service::run()) изолирован от остального кода, Дабы его дозволено было легко изменять.
И наконец неизменно помните, что .run() неизменно будет завершен, если огромнее нет операций для контроля, как показано в примере ниже:

io_service service_;
tcp::socket sock(service_);
sock.async_connect( ep, connect_handler);
service_.run();

В этом случае как только сокет установил соединение будет вызван connect_handler и service.run()завершится.
Если вы хотите, Дабы service.run() продолжил трудиться, вы обязаны предоставить ему огромнее работы. Есть два метода решения данной задачи. Одним из методов является увеличение нагрузки наconnect_handler, запустив еще одну асинхронную операцию.
2-й метод заключается в имитации некоторой его работы, применяя дальнейший код:

typedef boost::shared_ptr<io_service::work> work_ptr;
work_ptr dummy_work(new io_service::work(service_));

Приведенный выше код обеспечит непрерывную работу service_.run() до тех пор пока вы не вызоветеuseservice_.stop() либо dummy_work.reset(0); // destroy dummy_work.

Резюме.

Boost.Asio является трудной библиотекой, которая делает программирование сетей достаточно простым. Собрать ее легко. Она работает довольно отлично, чураясь применения макросов; предоставляется несколько макросов для включения опций вкл/выкл, но есть несколько пророческой, о которых невозможно забывать.
Boost.Asio поддерживает как синхронное так и асинхронное программирование. Эти два подхода дюже различные и вы обязаны предпочесть какой-то один и как дозволено прежде, так как переключение является достаточно трудным и подвержено ошибкам.
Если вы предпочли синхронный подход, то вы можете выбирать между исключениями и кодами ошибок, переход от исключений к кодам ошибок достаточно примитивен, нужно добавить еще один довод в вызов функции (код ошибки).
Boost.Asio служит не только для программирования сетей. У этой библиотеки есть несколько особенностей, которые делают ее больше ценной, такие как сигналы, таймеры и так дальше.
В дальнейшей главе мы будем вникать в уйма функций и классов Boost.Asio, предусматривающие сети. Помимо того мы узнаем несколько трюков об асинхронном программировании.

Ну вот и все на сегодня, если Вам понравилось, то я с удовольствием продолжу перевод. Обо всех примечаниях пишите в комментариях, но ответить я к сожалению не сумею (если только в лс), так как не имею инвайта.

Каждому везения!

 

Источник: programmingmaster.ru

 

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB