of owls and io objects
TRANSCRIPT
Of Owls and IO ObjectsOR network programming with ASIO
Felix MorgnerOct 25, 2017
Institute for SoftwareUniversity of Applied Sciences Rapperswil
What is ASIO
• A type of owl• Audio Stream Input/Output• Australian Security Intelligence Organisation• An asynchronous I/O toolkit for C++
1
What is ASIO
• A type of owl
• Audio Stream Input/Output• Australian Security Intelligence Organisation• An asynchronous I/O toolkit for C++
1
What is ASIO
• A type of owl• Audio Stream Input/Output
• Australian Security Intelligence Organisation• An asynchronous I/O toolkit for C++
1
What is ASIO
• A type of owl• Audio Stream Input/Output• Australian Security Intelligence Organisation
• An asynchronous I/O toolkit for C++
1
What is ASIO
• A type of owl• Audio Stream Input/Output• Australian Security Intelligence Organisation• An asynchronous I/O toolkit for C++
1
Brief History
• Architecture: Christopher Alexander 1977/79• A Place To Wait
• Beck & Cunningham 1987• GoF Patterns (Gamma et al.) 1994• Many more since then
4
Brief History
• Architecture: Christopher Alexander 1977/79• A Place To Wait
• Beck & Cunningham 1987
• GoF Patterns (Gamma et al.) 1994• Many more since then
4
Brief History
• Architecture: Christopher Alexander 1977/79• A Place To Wait
• Beck & Cunningham 1987• GoF Patterns (Gamma et al.) 1994
• Many more since then
4
Brief History
• Architecture: Christopher Alexander 1977/79• A Place To Wait
• Beck & Cunningham 1987• GoF Patterns (Gamma et al.) 1994• Many more since then
4
What Are Patterns
• Solutions to common problems• NOT code
• Descriptions of relevant forces• Language independent
5
What Are Patterns
• Solutions to common problems• NOT code• Descriptions of relevant forces
• Language independent
5
What Are Patterns
• Solutions to common problems• NOT code• Descriptions of relevant forces• Language independent
5
Misconceptions
• Patterns are invented
• GoF patterns are the only patterns• More patterns == Better software• Patterns have no drawbacks• Singleton is a good pattern
6
Misconceptions
• Patterns are invented• GoF patterns are the only patterns
• More patterns == Better software• Patterns have no drawbacks• Singleton is a good pattern
6
Misconceptions
• Patterns are invented• GoF patterns are the only patterns• More patterns == Better software
• Patterns have no drawbacks• Singleton is a good pattern
6
Misconceptions
• Patterns are invented• GoF patterns are the only patterns• More patterns == Better software• Patterns have no drawbacks
• Singleton is a good pattern
6
Misconceptions
• Patterns are invented• GoF patterns are the only patterns• More patterns == Better software• Patterns have no drawbacks• Singleton is a good pattern
6
Pattern Sources
• GoF
• POSA 1, 2, 3, 4• Security Patterns• Patterns for Fault Tolerant Software• Game Programming Patterns• Many, many more
7
Pattern Sources
• GoF• POSA 1, 2, 3, 4
• Security Patterns• Patterns for Fault Tolerant Software• Game Programming Patterns• Many, many more
7
Pattern Sources
• GoF• POSA 1, 2, 3, 4• Security Patterns
• Patterns for Fault Tolerant Software• Game Programming Patterns• Many, many more
7
Pattern Sources
• GoF• POSA 1, 2, 3, 4• Security Patterns• Patterns for Fault Tolerant Software
• Game Programming Patterns• Many, many more
7
Pattern Sources
• GoF• POSA 1, 2, 3, 4• Security Patterns• Patterns for Fault Tolerant Software• Game Programming Patterns
• Many, many more
7
Pattern Sources
• GoF• POSA 1, 2, 3, 4• Security Patterns• Patterns for Fault Tolerant Software• Game Programming Patterns• Many, many more
7
Two Patterns for Asynchronous I/O
• Reactor
• Notify when I/O is ready• “Consumer” must perform I/O
• Proactor• Notify when I/O is done• “Consumer” works with data
8
Two Patterns for Asynchronous I/O
• Reactor• Notify when I/O is ready• “Consumer” must perform I/O
• Proactor• Notify when I/O is done• “Consumer” works with data
8
Two Patterns for Asynchronous I/O
• Reactor• Notify when I/O is ready• “Consumer” must perform I/O
• Proactor
• Notify when I/O is done• “Consumer” works with data
8
Two Patterns for Asynchronous I/O
• Reactor• Notify when I/O is ready• “Consumer” must perform I/O
• Proactor• Notify when I/O is done• “Consumer” works with data
8
Two Patterns for Asynchronous I/O
• Reactor• Notify when I/O is ready• “Consumer” must perform I/O
• Proactor• Notify when I/O is done• “Consumer” works with data
8
Overview
• Created by Christopher Kohlhoff in 2003
• Part of the Boost libraries since 2008• Available on Linux, BSD, macOS, Windows, …• Based on the Proactor pattern• NOT only for asynchronous I/O
10
Overview
• Created by Christopher Kohlhoff in 2003• Part of the Boost libraries since 2008
• Available on Linux, BSD, macOS, Windows, …• Based on the Proactor pattern• NOT only for asynchronous I/O
10
Overview
• Created by Christopher Kohlhoff in 2003• Part of the Boost libraries since 2008• Available on Linux, BSD, macOS, Windows, …
• Based on the Proactor pattern• NOT only for asynchronous I/O
10
Overview
• Created by Christopher Kohlhoff in 2003• Part of the Boost libraries since 2008• Available on Linux, BSD, macOS, Windows, …• Based on the Proactor pattern
• NOT only for asynchronous I/O
10
Overview
• Created by Christopher Kohlhoff in 2003• Part of the Boost libraries since 2008• Available on Linux, BSD, macOS, Windows, …• Based on the Proactor pattern• NOT only for asynchronous I/O
10
ASIO Hello World
#include <asio.hpp>#include <chrono>#include <iostream>
int main() {auto && service = asio::io_service{};auto && timer = asio::steady_timer{service};
timer.expires_from_now(std::chrono::seconds{1});timer.async_wait([](auto error){std::cout << "timer fired!\n";
});
service.run();}
11
Disecting the Example
• Our Proactor• service = asio::io_service{};
• The I/O object• timer = asio::steady_timer{service};• Our asynchronous operation• timer.async_wait(...)• Our completion handler• [](auto error){ ... }
12
Disecting the Example
• Our Proactor• service = asio::io_service{};• The I/O object• timer = asio::steady_timer{service};
• Our asynchronous operation• timer.async_wait(...)• Our completion handler• [](auto error){ ... }
12
Disecting the Example
• Our Proactor• service = asio::io_service{};• The I/O object• timer = asio::steady_timer{service};• Our asynchronous operation• timer.async_wait(...)
• Our completion handler• [](auto error){ ... }
12
Disecting the Example
• Our Proactor• service = asio::io_service{};• The I/O object• timer = asio::steady_timer{service};• Our asynchronous operation• timer.async_wait(...)• Our completion handler• [](auto error){ ... }
12
It’s almost as simple
• OOTB Support for ICMP, TCP, UDP, IPv4/6, Multicast
• Includes support for resolving addresses• Also support TLS through OpenSSL• “Byte-based” and “Condition-based”
14
It’s almost as simple
• OOTB Support for ICMP, TCP, UDP, IPv4/6, Multicast• Includes support for resolving addresses
• Also support TLS through OpenSSL• “Byte-based” and “Condition-based”
14
It’s almost as simple
• OOTB Support for ICMP, TCP, UDP, IPv4/6, Multicast• Includes support for resolving addresses• Also support TLS through OpenSSL
• “Byte-based” and “Condition-based”
14
It’s almost as simple
• OOTB Support for ICMP, TCP, UDP, IPv4/6, Multicast• Includes support for resolving addresses• Also support TLS through OpenSSL• “Byte-based” and “Condition-based”
14
The connection class (head)
struct connection : std::enable_shared_from_this<connection> {// ... members
};
16
The connection class (data members)
struct connection : ... {
private:asio::ip::tcp::socket m_sock;asio::strand m_strand;std::array<char, 1024> m_buff{};std::deque<std::string> m_out{};
};
17
The connection class (ctor)
struct connection : ... {
connection(asio::ip::tcp::socket sock): m_sock{std::move(sock)}, m_strand{m_sock.get_io_service()} {
}
};
18
The connection class (starting communication)
struct connection : ... {
void start() {do_read();
}
};
19
The connection class (reading data)
struct connection : ... {
private:void do_read() {m_sock.async_read_some(asio::buffer(m_buff),
[&, self = shared_from_this()](auto error, auto read) {if(!error) {
auto begin = m_buff.data();auto end = begin + read;m_strand.post([&, data=std::string{begin, end}]{write(data);
});do_read();}
});}
};20
The connection class (writing data part 1)
struct connection : ... {
private:void write(std::string data) {m_out.push_back(data);
if(m_out.size() < 2) {do_write();
}}
};
21
The connection class (writing data part 2)
struct connection : ... {
private:void do_write() {asio::async_write(m_sock, asio::buffer(m_out.front()),
m_strand.wrap([&, self = shared_from_this()](auto error,auto written) {
m_out.pop_front();
if(!error) {if(!m_out.empty()) {do_write();
}}
}));}
};22
Review of the connection class
Connections:
• keep themselves alive• have a single input buffer• have an output queue
23
Review of the connection class
Connections:
• keep themselves alive
• have a single input buffer• have an output queue
23
Review of the connection class
Connections:
• keep themselves alive• have a single input buffer
• have an output queue
23
Review of the connection class
Connections:
• keep themselves alive• have a single input buffer• have an output queue
23
The server class (data members)
struct server {
private:asio::ip::tcp::acceptor m_acceptor;asio::ip::tcp::socket m_sock;
};
24
The server class (creation)
struct server {
server(asio::io_service & service): m_acceptor{service,
asio::ip::tcp::endpoint{asio::ip::tcp::v4(),4321}}
, m_sock{service} {}
};
25
The server class (accepting connections)
struct server {
private:void do_accept() {m_acceptor.async_accept(m_sock, [&](auto error){
if(!error) {auto conn = std::make_shared<connection>(std::move(m_sock)
);conn->start();do_accept();
}});
}};
27
Review of the server class
Our server:
• accepts new connections• creates connection objects• does not care about the connections
28
Review of the server class
Our server:
• accepts new connections
• creates connection objects• does not care about the connections
28
Review of the server class
Our server:
• accepts new connections• creates connection objects
• does not care about the connections
28
Review of the server class
Our server:
• accepts new connections• creates connection objects• does not care about the connections
28
Glueing it all together
auto && service = asio::io_service{};auto && server = ::server{service};
server.start();
29
Glueing it all together (contd.)
auto const cpus = std::thread::hardware_concurrency();auto pool = std::vector<std::future<void>>{cpus};
for(auto & future : pool) {future = std::async(std::launch::async, [&]{
service.run();});
}
31
It’s More Than Networking
• Signal handling• General worker pool• Stream I/O• Serial ports• Timers• File I/O (Windows)
34
It’s More Than Networking
• Signal handling
• General worker pool• Stream I/O• Serial ports• Timers• File I/O (Windows)
34
It’s More Than Networking
• Signal handling• General worker pool
• Stream I/O• Serial ports• Timers• File I/O (Windows)
34
It’s More Than Networking
• Signal handling• General worker pool• Stream I/O
• Serial ports• Timers• File I/O (Windows)
34
It’s More Than Networking
• Signal handling• General worker pool• Stream I/O• Serial ports
• Timers• File I/O (Windows)
34
It’s More Than Networking
• Signal handling• General worker pool• Stream I/O• Serial ports• Timers
• File I/O (Windows)
34
It’s More Than Networking
• Signal handling• General worker pool• Stream I/O• Serial ports• Timers• File I/O (Windows)
34
Signal handling
auto && signals = asio::signal_set(service, SIGINT);signals.add(SIGINT);signals.async_wait([&](auto error, auto signal){if(!error && !service.stopped()) {std::cout << "Received SIGINT. Terminating. " << '\n';service.stop();
}});
35
Worker Pool (running the workers)
auto const cpus = std::thread::hardware_concurrency();auto pool = std::vector<std::future<void>>{cpus};
for(auto & future : pool) {future = std::async(std::launch::async, [&]{
service.run();});
}
40
Conclusion
• ASIO is not a framework!
• It is not that scary• Provides rich I/O and event handling• Parts of it will be standard C++
41
Conclusion
• ASIO is not a framework!• It is not that scary
• Provides rich I/O and event handling• Parts of it will be standard C++
41
Conclusion
• ASIO is not a framework!• It is not that scary• Provides rich I/O and event handling
• Parts of it will be standard C++
41
Conclusion
• ASIO is not a framework!• It is not that scary• Provides rich I/O and event handling• Parts of it will be standard C++
41