일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- LOB
- Nebula
- JUCE 튜토리얼
- 운영체제
- C++ gui 라이브러리
- 리듬게임
- go channel
- 공룡책
- c++ heap
- Docker
- JUCE
- go
- 백준
- a tour of go
- C언어
- 알고리즘
- vim-go
- JUCE library
- 자료구조
- BOJ
- 코딩
- 프로그래밍
- gui
- C++ library
- OS
- 연결리스트
- tour of go
- C++ gui
- JUCE라이브러리
- C++
- Today
- Total
CafeM0ca
[C++]boost asio 튜토리얼 정리 본문
타이머 동기화 사용하기
asio에서 사용하는 모든 프로그램은 최소 하나의 boost::asio::io_context 객체가 필요하다. 이 클래스는 입출력 기능에 접근할 수 있다.
boost::asio::deadline_timer는 입출력 기능을 제공하며 항상 io_context를 첫번째 인자로 참조한다. 두번째 인자는 선언으로부터 설정한 n초 후에 만료된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //timer.cpp #include <iostream> #include <boost/asio.hpp> #include <boost/date_time/posix_time/posix_time.hpp> int main() { boost::asio::io_context io; boost::asio::deadline_timer t(io, boost::posix_time::seconds(5)); t.wait(); std::cout << "Hello, world!" << std::endl; return 0; } | cs |
타이머 비동기화 사용하기
asio 비동기 기능성은 비동기 준비가 완료되면 콜백함수가 호출된다. 이 프로그램에서 print는 비동기 대기가 끝나면 호출된다.
deadline_timer::async_wait() 함수를 호출하여 비동기 대기를 한다. 이 함수를 호출할때 print로 정의된 콜백 핸들러를 전달한다.
io_context::run() 맴버함수를 반드시 io_context 객체에 실행한다.
asio 라이브러리는 제공한다 콜백 핸들러가 오직 io_context::run() 함수를 호출하는 쓰레드에서만 호출된다는 보증을.
io_context::run() 함수를 호출하지 않으면 비동기 대기 완료를 위한 콜백이 호출되지 않는다.
중요한것은 io_context::run() 함수 호출전에 무언가 일을 줘야한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #include <iostream> #include <boost/asio.hpp> #include <boost/date_time/posix_time/posix_time.hpp> void print(const boost::system::error_code&) { std::cout << "Hello, world!" << std::endl; } int main() { boost::asio::io_context io; boost::asio::deadline_timer t(io,boost::posix_time::seconds(5)); t.async_wait(&print); io.run(); return 0; } | cs |
핸들러에 인자 바인딩하기
asio를 사용하여 타이머를 반복하도록 구현하려면 콜백함수에 만료시간을 바꿔주면 된다. 그러면 새롭게 비동기 대기를 시작한다.
pirnt함수에 2개의 매개변수를 추가한다.
- 타이머 객체를 가리키는 포인터
- 타이머를 6번 쓰면 멈추게하는 카운터
이렇게 추가함으로써 타이머에 시간 조절이 가능해진다. 1초씩 타이머를 줄이면서
이 프로그램은 카운터를 사용하는데 타이머가 6번째에 멈추기하기 위해서. 그러나 io_context에게 멈출것인지 명시적으로 묻지않는 것을 봐야한다.
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 | #include <iostream> #include <boost/asio.hpp> #include <boost/bind.hpp> #include <boost/date_time/posix_time/posix_time.hpp> void print(const boost::system::error_code&, boost::asio::deadline_timer *t,int *count) { if(*count < 5) { std::cout << *count << std::endl; ++(*count); t->expires_at(t->expires_at() + boost::posix_time::seconds(1)); t->async_wait(boost::bind(print,boost::asio::placeholders::error,t,count)); } } int main() { boost::asio::io_context io; int count = 0; boost::asio::deadline_timer t(io,boost::posix_time::seconds(1)); t.async_wait(boost::bind(print,boost::asio::placeholders::error,&t,&count)); io.run(); std::cout << "Final count is " << count << std::endl; return 0; } | cs |
멀티쓰레드 타이머
컴파일 옵션 : g++ -I(대문자 i) /path/path/boost_1_66_0 tiemr.cpp -o timer -l boost_system -l boost_thread -pthread
동기화 준비가 되면 각 콜백 핸들러는 boost::asio::io_service::strand 객체에게 "bound" 상태를 전달한다. strand객체에게 핸들러를 bind함으로써 동시에 실행되는것을 막는다.
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 | #include <iostream> #include <boost/asio.hpp> #include <boost/thread/thread.hpp> #include <boost/bind.hpp> #include <boost/date_time/posix_time/posix_time.hpp> class printer { public: printer(boost::asio::io_context& io) : strand_(io), timer1_(io, boost::posix_time::seconds(1)), timer2_(io, boost::posix_time::seconds(1)), count_(0) { timer2_.async_wait(boost::asio::bind_executor(strand_, boost::bind(&printer::print2, this))); timer1_.async_wait(boost::asio::bind_executor(strand_, boost::bind(&printer::print1, this))); } ~printer() { std::cout << "Final count is " << count_ << std::endl; } void print1() { if (count_ < 10) { std::cout << "Timer 1: " << count_ << std::endl; ++count_; timer1_.expires_at(timer1_.expires_at() + boost::posix_time::seconds(1)); timer1_.async_wait(boost::asio::bind_executor(strand_, boost::bind(&printer::print1, this))); } } void print2() { if (count_ < 10) { std::cout << "Timer 2: " << count_ << std::endl; ++count_; timer2_.expires_at(timer2_.expires_at() + boost::posix_time::seconds(1)); timer2_.async_wait(boost::asio::bind_executor(strand_, boost::bind(&printer::print2, this))); } } private: boost::asio::io_context::strand strand_; boost::asio::deadline_timer timer1_; boost::asio::deadline_timer timer2_; int count_; }; int main() { boost::asio::io_context io; printer p(io); boost::thread t(boost::bind(&boost::asio::io_context::run, &io)); io.run(); t.join(); return 0; } | cs |
모든 소스코드는 boost tutorial의 소스코드다. https://www.boost.org/doc/libs/1_66_0/doc/html/boost_asio/tutorial.html
2018/08/09 추가
daytime_client.cpp
이 클라이언트 프로그램은 아래의 동기화 서버 프로그램과 같이 돌아간다.
asio로 작동하는 프로그램에서는 io_context 객체가 최소한 하나가 필요하다. (io_service는 오래된 클래스다.)
ip::tcp::resolver
resolver는 쿼리 객체를 갖고 endpoints 리스트의 끝으로 바꾼다. 여기서는 argv[1]에 지정된 서버의 이름을 사용하여 쿼리를 만든다.
ip::tcp::resolver::iterator
resolver의 endpoints 리스트를 반환하기 위해 사용한다.
boost::asio::connect
위 과정에서 얻은것들은 IPv4와 IPv6 둘 다 될 수 있다. 작동하는것을 찾을 때 각각 해줘야한다. => 클라이언트의 특정 IP버전과 독립적으로 유지됨
boost::asio::connect는 이 과정을 자동으로 해준다.
ip::tcp::socket::read_some()
서버가 연결을 종료하면 ip::tcp::socket::read_some()은 boost::asio::error::eof()오류를 통해 종료한다.
daytime_server.cpp
asio를 사용해 동기화 서버 어플리케이션을 구현해보자.
make_daytime_string()을 통해 클라이언트에게 되보낼거다. 이 함수는 서버의 daytime을 재사용한다.
ip::tcp::acceptor 객체는 새로운 연결을 위해서 생성한다. TCP 13번포트로 ipv4버전을 응답받는다.
tcp::acceptor accpetor(io_context, tcp:;endpoint(tcp::v4(), 13));
위 서버 프로그램을 비동기로 작성해보자
클라이언트로부터 오는 요청을 서버의 io_context 객체가 사용하는데 io_context객체는 입출력 서비스와 소켓같은것을 제공한다.
'Programming > C++' 카테고리의 다른 글
[C++] 디폴트 매개변수 (0) | 2018.05.04 |
---|---|
[C++]ios 플래그와 포멧/조직자 (0) | 2018.04.08 |
[C++]boost asio g++ 컴파일 옵션 (0) | 2018.04.04 |
[JUCE]AudioAppComponent make 에러 (0) | 2018.03.01 |
[C++]boost라이브러리 설치와 컴파일 (0) | 2018.01.25 |