ã¿ãªããããã«ã¡ã¯ïŒ
John Torjoã®æ¬Boost.Asio C ++ Network Programmingã®ç¿»èš³ãç¶ããŠããŸãã
å
容ïŒ
Boost.Asioã®äœæè
ã¯çŽ æŽãããä»äºãããåæãã¹ãŸãã¯éåæãã¹ãéžæããããšã§ãã¢ããªã±ãŒã·ã§ã³ã«æé©ãªãã®ãéžæããæ©äŒãäžããŠãããŸããã
åã®ç« ã§ã¯ãåæã¯ã©ã€ã¢ã³ããåæãµãŒããŒãããã³ãããã®éåæãªãã·ã§ã³ãªã©ããã¹ãŠã®ã¿ã€ãã®ã¢ããªã±ãŒã·ã§ã³ã®ãã¬ãŒã ã¯ãŒã¯ãèŠãŠããŸããã ãããã®ãããããã¢ããªã±ãŒã·ã§ã³ã®åºç€ãšããŠäœ¿çšã§ããŸãã åã¿ã€ãã®ã¢ããªã±ãŒã·ã§ã³ã®è©³çްã詳ãã調ã¹ãå¿
èŠãããå Žåã¯ãèªã¿é²ããŠãã ããã
åæããã°ã©ãã³ã°ãšéåæããã°ã©ãã³ã°ãæ··åšããã
Boost.Asioã©ã€ãã©ãªã䜿çšãããšãåæããã°ã©ãã³ã°ãšéåæããã°ã©ãã³ã°ãæ··åšãããããšãã§ããŸãã å人çã«ã¯ãããã¯æªãèãã ãšæããŸãããBoost.Asioã¯ãäžè¬çã«C ++ãšåæ§ã«ãå¿
èŠã«å¿ããŠèªåèªèº«ãæã¡ãŸãã
ç¹ã«ã¢ããªã±ãŒã·ã§ã³ãéåæã§å®è¡ãããå Žåãç°¡åã«ãã©ããã«é¥ãããšããããŸãã ããšãã°ãéåæã®æžãèŸŒã¿æäœã«å¿çããŠãããšãã°éåæã®èªã¿åãæäœãå®è¡ããŸãã
io_service service; ip::tcp::socket sock(service); ip::tcp::endpoint ep( ip::address::from_string("127.0.0.1"), 8001); void on_write(boost::system::error_code err, size_t bytes) { char read_buff[512]; read(sock, buffer(read_buff)); } async_write(sock, buffer("echo"), on_write);
確ãã«åæèªã¿åãæäœã¯çŸåšã®ã¹ã¬ããããããã¯ãããããä»ã®äžå®å
šãªéåææäœã¯ã¹ã¿ã³ãã€ã¢ãŒãã«ãªããŸãïŒãã®ã¹ã¬ããã®å ŽåïŒã ããã¯æªãã³ãŒãã§ãããã¢ããªã±ãŒã·ã§ã³ã®é床ãäœäžãããããããã¯ããããããå¯èœæ§ããããŸãïŒéåæã¢ãããŒãã䜿çšããäž»ãªç®çã¯ããããã¯ãåé¿ããããšã§ãããããã£ãŠãåææäœã䜿çšãããšãããã¯æåŠãããŸãïŒ åæã¢ããªã±ãŒã·ã§ã³ã䜿çšããŠããå Žåã¯ãéåæã®èªã¿åããŸãã¯æžãèŸŒã¿æäœã䜿çšããããšã¯ã»ãšãã©ãããŸãããåæçã«èããããšã¯ãæ¢ã«ç·åœ¢ã«èããããšãæå³ããŸãïŒAãBãCãªã©ïŒã
ç§ã®æèŠã§ã¯ãåææäœãšéåææäœã飿ºã§ããå¯äžã®ã±ãŒã¹ã¯ãããšãã°ãåæãããã¯ãŒã¯ãšããŒã¿ããŒã¹ããã®å
¥åºåã®éåææäœãªã©ãå®å
šã«åé¢ãããŠããå Žåã§ãã
ã¯ã©ã€ã¢ã³ããããµãŒããŒãžããŸãã¯ãã®éãžã®ã¡ãã»ãŒãžã®é
ä¿¡
åªããã¯ã©ã€ã¢ã³ã/ãµãŒããŒã¢ããªã±ãŒã·ã§ã³ã®éåžžã«éèŠãªéšåã¯ãã¡ãã»ãŒãžãïŒãµãŒããŒããã¯ã©ã€ã¢ã³ããžãããã³ã¯ã©ã€ã¢ã³ããããµãŒããŒãžïŒååŸã«é
ä¿¡ããããšã§ãã ã¡ãã»ãŒãžãèå¥ãããã®ãæå®ããå¿
èŠããããŸãã ã€ãŸããçä¿¡ã¡ãã»ãŒãžãèªã¿åãããŠãããšãã«ãã¡ãã»ãŒãžãå®å
šã«èªã¿åãããããšãã©ã®ããã«ããŠç¥ãããšãã§ããŸããïŒ
ã¡ãã»ãŒãžã®çµãããå€å¥ããå¿
èŠããããŸãïŒæåã¯å€å¥ã容æã§ããããã¯æåŸã®ã¡ãã»ãŒãžã®çµããã®åŸã«åä¿¡ãããæåã®ãã€ãã§ãïŒããããã»ã©ç°¡åã§ã¯ãªãããšãããããŸãã
次ã®ããšãã§ããŸãã
- åºå®ãµã€ãºã®ã¡ãã»ãŒãžãäœæããïŒããã¯è¯ãèãã§ã¯ãããŸãããããã«ããŒã¿ãéä¿¡ããå¿
èŠãããå Žåã¯ã©ãããŸããïŒïŒ
- ã\ nããã\ 0ããªã©ãã¡ãã»ãŒãžãçµäºããç¹å®ã®æåãäœæããŸã
- ã¡ãã»ãŒãžã®é·ããã¡ãã»ãŒãžãã¬ãã£ãã¯ã¹ãšããŠæå®ããŸãã
æ¬å
šäœãéããŠããåã¡ãã»ãŒãžã®æåŸã«ã\ nãæåã䜿çšããããšã«ããŸãããã ãããã£ãŠãã¡ãã»ãŒãžãèªããšã次ã®ã³ãŒããã©ã°ã¡ã³ãã瀺ãããŸãã
char buff_[512];
èªè
ã®ç·Žç¿ãšããŠãã¡ãã»ãŒãžãã¬ãã£ãã¯ã¹ãšããŠé·ãã®æç€ºãæ®ãããšã¯éåžžã«ç°¡åã§ãã
ã¯ã©ã€ã¢ã³ãã¢ããªã±ãŒã·ã§ã³ã®åæI / O
ååãšããŠãåæã¯ã©ã€ã¢ã³ãã«ã¯2ã€ã®ã¿ã€ãããããŸãã
- ãµãŒããŒã«äœããèŠæ±ããå¿çãèªã¿åã£ãŠåŠçããŸãã æ¬¡ã«ãä»ã®äœããªã©ãèŠæ±ããŸãã ããã¯åºæ¬çã«åæã¯ã©ã€ã¢ã³ãã§ãããåã®ç« ã§èª¬æããŸããã
- ãµãŒããŒããçä¿¡ã¡ãã»ãŒãžãèªã¿åããåŠçããŠå¿çãæžã蟌ã¿ãŸãã æ¬¡ã«ã次ã®çä¿¡ã¡ãã»ãŒãžãªã©ãèªã¿åããŸãã

äž¡æ¹ã®ã·ããªãªã¯ãæ¬¡ã®æŠç¥ã䜿çšããŸããèŠæ±ãäœæãã-å¿çãèªã¿åããŸãã ã€ãŸããäžæ¹ã®åœäºè
ãèŠæ±ãè¡ãã仿¹ã®åœäºè
ãå¿çããŸãã ããã¯ãã¯ã©ã€ã¢ã³ã/ãµãŒããŒã¢ããªã±ãŒã·ã§ã³ãå®è£
ããç°¡åãªæ¹æ³ã§ãããããããå§ãã§ãã
Mambo Jamboã®ã¯ã©ã€ã¢ã³ã/ãµãŒããŒããã€ã§ãäœæã§ããŸããåãµã€ãã¯ãã€ã§ã奜ããªãšãã«æžã蟌ã¿ãŸããããã®ãã¹ãçœå®³ã«ã€ãªããå¯èœæ§ãéåžžã«é«ããªããŸãïŒã¯ã©ã€ã¢ã³ããŸãã¯ãµãŒããŒããããã¯ããããšãã«äœãèµ·ãã£ãã®ããã©ããã£ãŠç¥ãã®ã§ããïŒïŒã
以åã®ã¹ã¯ãªããã¯åãããã«èŠãããããããŸããããéåžžã«ç°ãªã£ãŠããŸãïŒ
- æåã®ã±ãŒã¹ã§ã¯ããµãŒããŒã¯ãªã¯ãšã¹ãã«å¿çããŸãïŒãµãŒããŒã¯ã¯ã©ã€ã¢ã³ãããã®ãªã¯ãšã¹ããåŸ
æ©ãããªã¯ãšã¹ãã«å¿çããŸãïŒã ããã¯ãã¯ã©ã€ã¢ã³ãããµãŒããŒããã®èŠæ±ã«å¿ããŠå¿
èŠãªãã®ãåä¿¡ããå Žåã®ãã«ã®ãããªæ¥ç¶ã§ãã
- åŸè
ã®å ŽåããµãŒããŒã¯å¿çããã¯ã©ã€ã¢ã³ãã€ãã³ããéä¿¡ããŸãã ããã¯ããµãŒããŒãã¯ã©ã€ã¢ã³ãã«éç¥/ã€ãã³ããããã·ã¥ãããšãã®ããã·ã¥ã®ãããªæ¥ç¶ã§ãã
åºæ¬çã«ã¯ãéåžžã®æšæºãšåæ§ã«ãéçºã容æã«ãããã«åã®ã¯ã©ã€ã¢ã³ã/ãµãŒããŒã¢ããªã±ãŒã·ã§ã³ã«ééããŸãã
ãããã®2ã€ã®ã¢ãããŒããæ··åšãããããšãã§ããŸãããªã³ããã³ãïŒã¯ã©ã€ã¢ã³ããµãŒããŒïŒã§ååŸããèŠæ±ïŒãµãŒããŒã¯ã©ã€ã¢ã³ãïŒãããã·ã¥ããŸãããããã¯å°é£ã§ãããåé¿ããããšããå§ãããŸãã ãããã®2ã€ã®ã¢ãããŒããæ··åããåé¡ããããŸã;æŠç¥ã䜿çšããŠèŠæ±ãè¡ãå Žåãçããèªãã§ãã ãã; 以äžãçºçããå¯èœæ§ããããŸãã
- ã¯ã©ã€ã¢ã³ãã¯æžã蟌ã¿ãŸãïŒãªã¯ãšã¹ããè¡ããŸãïŒ
- ãµãŒããŒã¯æžã蟌ã¿ãŸãïŒã¯ã©ã€ã¢ã³ãã«éç¥ãéä¿¡ããŸãïŒ
- ã¯ã©ã€ã¢ã³ãã¯ããµãŒããŒãæžã蟌ãã å
容ãèªã¿åãããããèŠæ±ãžã®å¿çãšããŠè§£éããŸã
- ãµãŒããŒã¯ãã¯ã©ã€ã¢ã³ããæ°ããèŠæ±ãè¡ã£ããšãã«å°çããã¯ã©ã€ã¢ã³ãããã®å¿çãåŸ
æ©ããŠãããã¯ããŸã
- ã¯ã©ã€ã¢ã³ãã¯æžã蟌ã¿ãŸãïŒæ°ããèŠæ±ãäœæããŸãïŒ
- ãµãŒããŒã¯ããã®èŠæ±ãåŸ
æ©ããŠããå¿çãšããŠè§£éããŸã
- ã¯ã©ã€ã¢ã³ãã¯ãããã¯ãããŸãïŒãµãŒããŒã¯ãã¯ã©ã€ã¢ã³ãã®èŠæ±ãéç¥ãžã®å¿çãšããŠè§£éããããããµãŒããŒã¯å¿çãè¿ããŸããïŒã
ãã«åã®ã¯ã©ã€ã¢ã³ã/ãµãŒããŒã¢ããªã±ãŒã·ã§ã³ã§ã¯ãåã®ã·ããªãªãç°¡åã«åé¿ã§ããŸãã ã¯ã©ã€ã¢ã³ãããµãŒããŒãšã®æ¥ç¶ã確èªãããšãã«ãããšãã°5ç§ããšã«pingããã»ã¹ãå®è£
ããããšã§ãããã·ã¥ã®ãããªåäœãã·ãã¥ã¬ãŒãã§ããŸãã ãµãŒããŒã¯ãå ±åãããã®ããªãå Žåã¯ping_okãéç¥ããã€ãã³ããããå Žåã¯ping_ [event_name]ãªã©ã®å¿çãè¿ããŸãã ãã®åŸãã¯ã©ã€ã¢ã³ãã¯ãã®ã€ãã³ããåŠçããæ°ãããªã¯ãšã¹ããéå§ã§ããŸãã
ç¹°ãè¿ããŸãããåã®ã¹ã¯ãªããã¯åã®ç« ã®åæã¯ã©ã€ã¢ã³ãã瀺ããŠããŸãã ã¡ã€ã³ã«ãŒãïŒ
void loop() {
æåŸã®ã·ããªãªã«åãããŠå€æŽããŸãã
void loop() { while ( started_) { read_notification(); write_answer(); } } void read_notification() { already_read_ = 0; read(sock_, buffer(buff_), boost::bind(&talk_to_svr::read_complete, this, _1, _2)); process_notification(); } void process_notification() {
ãµãŒããŒã¢ããªã±ãŒã·ã§ã³ã®åæI / O
ã¯ã©ã€ã¢ã³ããšåæ§ã«ããµãŒããŒã«ã¯2ã€ã®ã¿ã€ãããããåã®ã»ã¯ã·ã§ã³ã®2ã€ã®ã·ããªãªã«å¯Ÿå¿ããŠããŸãã ç¹°ãè¿ããŸãããã©ã¡ãã®ã·ããªãªãæŠç¥ã䜿çšããŠããŸãããªã¯ãšã¹ããäœæããã¬ã¹ãã³ã¹ãèªã¿åããŸãã

æåã®ã·ããªãªã¯ãåã®
ç« ã§å®è£
ããåæãµãŒããŒã§ãã ããããã³ã°ãåé¿ãããã®ã§ãåæçã«äœæ¥ããŠããå Žåã¯ãèŠæ±ãå®å
šã«èªã¿åãããšã¯ç°¡åã§ã¯ãããŸããïŒåžžã«å¯èœãªéãèªã¿åããŸãïŒã
void read_request() { if ( sock_.available()) already_read_ += sock_.read_some(buffer(buff_ + already_read_, max_msg âalready_read_)); }
ã¡ãã»ãŒãžãå®å
šã«èªã¿åãããåŸãåçŽã«ã¡ãã»ãŒãžãåŠçããŠã¯ã©ã€ã¢ã³ãã«å¿çããŸãã
void process_request() { bool found_enter = std::find(buff_, buff_ + already_read_, '\n') < buff_ + already_read_; if ( !found_enter) return;
ãµãŒããŒãããã·ã¥åãµãŒããŒã«ãããå Žåã¯ã次ã®ããã«å€æŽããŸãã
typedef std::vector<client_ptr> array; array clients; array notify; std::string notify_msg; void on_new_client() {
on_new_client()
颿°ã¯1ã€ã®ã€ãã³ãã®é¢æ°ã§ããããã¹ãŠã®ã¯ã©ã€ã¢ã³ãã«éç¥ããå¿
èŠããããŸãã
notify_clients
ã¯ããã®ã€ãã³ãã«ãµãã¹ã¯ã©ã€ãããŠããã¯ã©ã€ã¢ã³ãã«éç¥ãã颿°ã§ãã ãµãŒããŒã¯ã¡ãã»ãŒãžãéä¿¡ããŸãããåã¯ã©ã€ã¢ã³ãããã®å¿çãåŸ
æ©ããŸãããããã«ããããããã¯ãçºçããå¯èœæ§ããããŸãã ã¯ã©ã€ã¢ã³ãããå¿çãæ¥ããšãã¯ã©ã€ã¢ã³ãã¯ãããéç¥ãžã®åçã§ããããšãäŒããããšãã§ããŸãïŒãããŠãããæ£ããåŠçã§ããŸãïŒã
åæãµãŒããŒã®ã¹ã¬ãã
ããã¯éåžžã«éèŠãªèŠçŽ ã§ãã顧客ã®åŠçã«ããã€ã®ã¹ã¬ãããå²ãåœãŠãã®ã§ããããïŒ
åæãµãŒããŒã®å Žåãæ°ããæ¥ç¶ãåŠçããã¹ã¬ãããå°ãªããšã1ã€å¿
èŠã§ãã
void accept_thread() { ip::tcp::acceptor acceptor(service, ip::tcp::endpoint(ip::tcp::v4(),8001)); while ( true) { client_ptr new_( new talk_to_client); acceptor.accept(new_->sock()); boost::recursive_mutex::scoped_lock lk(cs); clients.push_back(new_); } }
æ¢åã®ã客æ§ã®å ŽåïŒ
- çéã§è¡ãããšãã§ããŸãã ãããæãç°¡åãªæ¹æ³ã§ããã 第4ç« ã§åæãµãŒããŒãå®è£
ãããšãã«éžæããŸããã 100ã200ã®åææ¥ç¶ã«ç°¡åã«å¯Ÿå¿ã§ããŸããããã以äžã®å ŽåããããŸããããã¯ãã»ãšãã©ã®å Žåã«ååã§ãã
- ã¯ã©ã€ã¢ã³ãããšã«ãããŒãäœæã§ããŸãã ããã¯ãã£ãã«è¯ããªãã·ã§ã³ã§ã¯ãããŸãããå€ãã®ã¹ã¬ãããè²»ããããããã°ãå°é£ã«ããããšããããŸãããããã200人以äžã®åæãŠãŒã¶ãŒãåŠçããŸãããããã«éçã«éããŸãã
- æ¢åã®é¡§å®¢ãåŠçããããã«ãåºå®æ°ã®ã¹ã¬ãããäœæã§ããŸãã
3çªç®ã®ãªãã·ã§ã³ã¯ãåæãµãŒããŒã«å®è£
ããã®ãéåžžã«å°é£ã§ãã
talk_to_client
ã¯ã©ã¹å
šäœãã¹ã¬ããã»ãŒãã«ãªããŸããã æ¬¡ã«ãã©ã®ã¹ã¬ãããã©ã®ã¯ã©ã€ã¢ã³ããåŠçããããç¥ãããã®ç¹å¥ãªã¡ã«ããºã ãå¿
èŠã«ãªããŸãã ããã«ã¯2ã€ã®ãªãã·ã§ã³ããããŸãã
- ç¹å®ã®ã¯ã©ã€ã¢ã³ããç¹å®ã®ã¹ã¬ããã«å²ãåœãŠãŸãã ããšãã°ãæåã®ã¹ã¬ããã¯æåã®20åã®ã¯ã©ã€ã¢ã³ããåŠçãã2çªç®ã®ã¹ã¬ããã¯21ã40åã®ã¯ã©ã€ã¢ã³ããåŠçããŸãã 顧客ã䜿çšäžã®å Žåãå€ãã®æ¢åã®é¡§å®¢ããæœåºããŸãã ãã®ã¯ã©ã€ã¢ã³ããšååããåŸã圌ããªã¹ãã«æ»ããŸããã åã¹ã¬ããã¯ãæ¢åã®ãã¹ãŠã®ã¯ã©ã€ã¢ã³ãã埪ç°ããæåã®ã¯ã©ã€ã¢ã³ããå®å
šãªãªã¯ãšã¹ãã§åŠçãïŒã¯ã©ã€ã¢ã³ãããã®çä¿¡ã¡ãã»ãŒãžãå®å
šã«èªã¿åããŸãïŒãããã«å¿çããŸãã
- ãµãŒããŒãå¿çã忢ããå ŽåããããŸãã
- æåã®ã±ãŒã¹ã§ã¯ã1ã€ã®ã¹ã¬ããã§åŠçãããè€æ°ã®ã¯ã©ã€ã¢ã³ããåæã«èŠæ±ãäœæãã1ã€ã®ã¹ã¬ããã¯äžåºŠã«1ã€ã®èŠæ±ããåŠçã§ããŸããã ãã ãããã®å Žåã¯äœãã§ããŸããã
- 2çªç®ã®ã±ãŒã¹ã§ã¯ãã¹ã¬ãããããå€ãã®ãªã¯ãšã¹ããåæã«åãåããŸãã ãã®å ŽåãåçŽã«æ°ããã¹ã¬ãããäœæããŠè² è·ãåŠçã§ããŸãã
å
ã®
answer_to_client
颿°ã«äŒŒã次ã®ã³ãŒãã¯ãæåŸã®ã¹ã¯ãªãããå®è£
ããæ¹æ³ã瀺ããŠããŸãã
struct talk_to_client : boost::enable_shared_from_this<talk_to_client> { ... void answer_to_client() { try { read_request(); process_request(); } catch ( boost::system::system_error&) { stop(); } } };
以äžã«ç€ºãããã«å€æŽããŸãã
struct talk_to_client : boost::enable_shared_from_this<talk_to_client> { boost::recursive_mutex cs; boost::recursive_mutex cs_ask; bool in_process; void answer_to_client() { { boost::recursive_mutex::scoped_lock lk(cs_ask); if ( in_process) return; in_process = true; } { boost::recursive_mutex::scoped_lock lk(cs); try { read_request(); process_request(); } catch ( boost::system::system_error&) { stop(); } } { boost::recursive_mutex::scoped_lock lk(cs_ask); in_process = false; } } };
ã¯ã©ã€ã¢ã³ããåŠçããéããã®
in_process
ã€ã³ã¹ã¿ã³ã¹ã¯
true
ã«èšå®ãããä»ã®ã¹ã¬ããã¯ãã®ã¯ã©ã€ã¢ã³ããç¡èŠããŸãã 远å ã®ããŒãã¹ã¯ã
handle_clients_thread()
颿°ã倿Žã§ããªãããšã§ãã å¿
èŠãªã ã
handle_clients_thread()
颿°ãäœæã§ããŸãã
ã¯ã©ã€ã¢ã³ãã¢ããªã±ãŒã·ã§ã³ã®éåæI / O
ã¡ã€ã³ã®ã¯ãŒã¯ãããŒã¯ãåæã¯ã©ã€ã¢ã³ãã¢ããªã±ãŒã·ã§ã³ã®åãããã»ã¹ã«äŒŒãŠããŸãããBoost.Asioãå
async_write
ãš
async_write
éã«ãããšããéãããããŸãã

æåã®ã·ããªãªã¯ã
第4ç« ã®éåæã¯ã©ã€ã¢ã³ããå®è£
ããããã®ãšåãã§ãã åéåææäœã®æåŸã«ã
service.run()
颿°ããã®ã¢ã¯ãã£ããã£ãçµäºããªãããã«ãå¥ã®éåææäœãéå§ããå¿
èŠãããããšã«æ³šæããŠãã ããã
æåã®ã·ããªãªã2çªç®ã®ã·ããªãªã«ããã«ã¯ã次ã®ã³ãŒããã©ã°ã¡ã³ãã䜿çšããå¿
èŠããããŸãã
void on_connect() { do_read(); } void do_read() { async_read(sock_, buffer(read_buffer_), MEM_FN2(read_complete,_1,_2), MEM_FN2(on_read,_1,_2)); } void on_read(const error_code & err, size_t bytes) { if ( err) stop(); if ( !started() ) return; std::string msg(read_buffer_, bytes); if ( msg.find("clients") == 0) on_clients(msg); else ... } void on_clients(const std::string & msg) { std::string clients = msg.substr(8); std::cout << username_ << ", new client list:" << clients ; do_write("clients ok\n"); }
æ¥ç¶ã«æåãããšããã«ããµãŒããŒããã®èªã¿åããéå§ããããšã«æ³šæããŠãã ããã å
on_[event]
颿°ã¯çµäºãããµãŒããŒã«å¿çãæžã蟌ã¿ãŸãã
éåæã¢ãããŒãã®å©ç¹ã¯ãBoost.Asioã䜿çšããŠãããã¯ãŒã¯I / Oãšä»ã®éåææäœãæ··åšãããŠãããããã¹ãŠãæŽçã§ããããšã§ãã ã¹ããªãŒã ã¯åæã¹ããªãŒã ã»ã©æç¢ºã§ã¯ãããŸããããå®éã«ã¯åæã¹ããªãŒã ãšèããããšãã§ããŸãã
WebãµãŒããŒãããã¡ã€ã«ãèªã¿åããããŒã¿ããŒã¹ã«ïŒéåæã§ïŒä¿åãããšããŸãã æ¬¡ã®ãããŒãã£ãŒãã«ç€ºãããã«ãå®éã«ããã«ã€ããŠèããããšãã§ããŸãã

ãµãŒããŒã¢ããªã±ãŒã·ã§ã³ã®éåæI / O
åã³ããŠããã¿ã¹ãª2ã€ã®ã±ãŒã¹ãæåã®ã¹ã¯ãªããïŒãã«ïŒãš2çªç®ã®ã¹ã¯ãªããïŒããã·ã¥ïŒïŒ

æåã®éåæãµãŒããŒã¹ã¯ãªããã¯ãåã®
ç« ã§å®è£
ãããŸããã åéåææäœã®æåŸã«ã
service.run()
ãæéåãã«ãªããªãããã«å¥ã®éåææäœãéå§ããå¿
èŠããããŸãã
ããªãã³ã°ãããã³ãŒããã¬ãŒã ã¯ãŒã¯ã次ã«ç€ºããŸãã 以äžã¯ã
talk_to_client
ã¯ã©ã¹ã®ãã¹ãŠã®ã¡ã³ããŒã§ãã
void start() { ... do_read();
ç°¡åã«èšããšãèªã¿åãæäœãå®äºãããšããã«ãèªã¿åãæäœãåžžã«åŸ
æ©ããã¡ãã»ãŒãžãåŠçããŠã¯ã©ã€ã¢ã³ãã«å¿çããŸãã
åã®ã³ãŒããããã·ã¥ãµãŒããŒã«å€æããŸãã
void start() { ... on_new_client_event(); } void on_new_client_event() { std::ostringstream msg; msg << "client count " << clients.size(); for ( array::const_iterator b = clients.begin(), e = clients.end();b != e; ++b) (*b)->do_write(msg.str()); } void on_read(const error_code & err, size_t bytes) { std::string msg(read_buffer_, bytes);
on_new_client_event
ãªã©ã®ã€ãã³ããçºçãããšããã®ã€ãã³ãã«ã€ããŠéç¥ããå¿
èŠããããã¹ãŠã®ã¯ã©ã€ã¢ã³ãã«ã¡ãã»ãŒãžãéä¿¡ãããŸãã åçãããšãåä¿¡ããã€ãã³ããåŠçããããšãããããŸãã ç§ãã¡ã¯åžžã«æ°ãã顧客ãåŸ
ã£ãŠãããããã€ãã³ããéåæçã«åŸ
ã€ããšã¯æ±ºããŠãããŸããïŒãããã£ãŠ
service.run()
ã¯åäœãçµäºããŸããïŒã
éåæãµãŒããŒã®ã¹ã¬ãã
éåæãµãŒããŒã¯ç¬¬4ç« ã§èª¬æããŸãããããã¹ãŠã
main()
颿°ã§çºçãããããã·ã³ã°ã«ã¹ã¬ããã§ãã
int main() { talk_to_client::ptr client = talk_to_client::new_(); acc.async_accept(client->sock(), boost::bind(handle_accept,client,_1)); service.run(); }
éåæã¢ãããŒãã®å©ç¹ã¯ãã·ã³ã°ã«ã¹ã¬ããããŒãžã§ã³ãããã«ãã¹ã¬ããããŒãžã§ã³ãžã®ç§»è¡ã容æãªããšã§ãã å°ãªããšã顧客ãåæã«200人以äžã«ãªããŸã§ããã€ã§ãçéã§è¡ãããšãã§ããŸãã æ¬¡ã«ã1ã€ã®ã¹ã¬ãããã100ã®ã¹ã¬ããã«åãæ¿ããã«ã¯ã次ã®ã³ãŒããã©ã°ã¡ã³ãã䜿çšããå¿
èŠããããŸãã
boost::thread_group threads; void listen_thread() { service.run(); } void start_listen(int thread_count) { for ( int i = 0; i < thread_count; ++i) threads.create_thread( listen_thread); } int main(int argc, char* argv[]) { talk_to_client::ptr client = talk_to_client::new_(); acc.async_accept(client->sock(), boost::bind(handle_accept,client,_1)); start_listen(100); threads.join_all(); }
ãã¡ããããã«ãã¹ã¬ããã®äœ¿çšãéå§ããããã¹ã¬ããã»ãŒãã«ã€ããŠèããå¿
èŠããããŸãã ã¹ã¬ããAã§
async_*
ãåŒã³åºããå Žåã§ãããããå®äºããããã®æé ãã¹ã¬ããBã§åŒã³åºãããšãã§ããŸãïŒã¹ã¬ããBã
service.run()
åŒã³åºãéãïŒã ããèªäœã¯åé¡ã§ã¯ãããŸããã è«çã·ãŒã±ã³ã¹ã«åŸãéããã€ãŸã
async_read()
ãã
on_read()
ã
on_read()
ãã
process_reques
tã
process_request
ãã
async_write()
ã
async_write()
ãã
on_write()
ã
on_write()
ãã
on_write()
ãã
async_read()
on_write()
ã«
async_read()
ã
talk_to_client
ã¯ã©ã¹ãåŒã³åºã
public
颿°ã¯ãããŸãããç°ãªãã¹ã¬ããã§ç°ãªã颿°ãåŒã³åºãããšãã§ããŸããããããã¯åŒãç¶ãé çªã«åŒã³åºãããŸãã ãããã£ãŠããã¥ãŒããã¯ã¹ã¯å¿
èŠãããŸããã
ãã ããããã¯ãã¯ã©ã€ã¢ã³ãã«å¯ŸããŠä¿çã§ããéåææäœã¯1ã€ã ãã§ããããšãæå³ããŸãã ããæç¹ã§ãã¯ã©ã€ã¢ã³ãã«2ã€ã®ä¿çäžã®éåæé¢æ°ãããå Žåããã¥ãŒããã¯ã¹ãå¿
èŠã«ãªããŸãã 2ã€ã®ä¿çäžã®æäœã¯ã»ãŒåæã«å®äºããããšãã§ããæçµçã«ã¯2ã€ã®ç°ãªãã¹ã¬ããã§åæã«ãã³ãã©ãŒãåŒã³åºãããšãã§ããããã§ãã ãããã£ãŠãã¹ã¬ããã»ãŒããã€ãŸããã¥ãŒããã¯ã¹ãå¿
èŠã§ãã
éåæãµãŒããŒã§ã¯ãå®éã«ã¯åæã«2ã€ã®ä¿çäžã®æäœããããŸãã
void do_read() { async_read(sock_, buffer(read_buffer_), MEM_FN2(read_complete,_1,_2), MEM_FN2(on_read,_1,_2)); post_check_ping(); } void post_check_ping() { timer_.expires_from_now(boost::posix_time::millisec(5000)); timer_.async_wait( MEM_FN(on_check_ping)); }
èªã¿åãæäœãå®è¡ãããšããéåæçã«äžå®æéãã®å®äºãåŸ
ã¡ãŸãã ãããã£ãŠãã¹ã¬ããã»ãŒããå¿
èŠã§ãã ç§ã®ã¢ããã€ã¹ã¯ããã«ãã¹ã¬ãããªãã·ã§ã³ãéžæããå Žåã¯ãã¯ã©ã¹ãæåããã¹ã¬ããã»ãŒãã«ããããšã§ãã ããã¯éåžžãããã©ãŒãã³ã¹ãäœäžãããŸããïŒãã¡ããããã確èªã§ããŸãïŒã ãŸãããã«ãã¹ããªãŒã ãã¹ã䜿çšããå Žåã¯ãæåãããããå®è¡ããŠãã ããã ãããã£ãŠãåææ®µéã§æœåšçãªåé¡ãçºçããŸãã åé¡ãèŠã€ãã£ããããã«ãæåã«ç¢ºèªããå¿
èŠãããã®ã¯ãå®è¡äžã®1ã€ã®ã¹ã¬ããã§ãããèµ·ãã£ãŠããããšã§ããïŒ ã¯ãã®å Žåãããã¯ç°¡åã§ããããã°ããã ãã§ãã ãã以å€ã®å Žåã¯ãããããããã€ãã®æ©èœããã¥ãŒããã¯ã¹ããã®ãå¿ããŠããŸããã
ãã®äŸã§ã¯ã¹ã¬ããã»ãŒããå¿
èŠãªãããmutexã䜿çšããŠ
talk_to_client
ã倿Žã
talk_to_client
ã ããã«ãã³ãŒãå
ã§äœåºŠãåç
§ããã¯ã©ã€ã¢ã³ãã®é
åããããç¬èªã®ãã¥ãŒããã¯ã¹ãå¿
èŠã§ãã
ãããããã¯ãšã¡ã¢ãªç Žæãåé¿ããããšã¯ããã»ã©ç°¡åã§ã¯ãããŸããã
update_clients_changed()
颿°ã倿Žããæ¹æ³ã¯
update_clients_changed()
ã§ãã
void update_clients_changed() { array copy; { boost::recursive_mutex::scoped_lock lk(clients_cs); copy = clients; } for( array::iterator b = copy.begin(), e = copy.end(); b != e; ++b) (*b)->set_clients_changed(); }
åé¿ãããã®ã¯ã2ã€ã®ãã¥ãŒããã¯ã¹ãåæã«ããã¯ãããããšã§ãïŒãããããã¯ç¶æ
ã«ãªãå¯èœæ§ããããŸãïŒã ãã®å Žåã
clients_cs
ãšclient
clients_cs
mutexãåæã«ããã¯ãããªãããã«ããŸãã
éåææäœ
Boost.Asioã§ã¯ãä»»æã®æ©èœãéåæã§å®è¡ããããšãã§ããŸãã æ¬¡ã®ã³ãŒãã¹ããããã䜿çšããã ãã§ãã
void my_func() { ... } service.post(my_func);
service.run()
ãåŒã³åºãã¹ã¬ããã®1ã€ã§
my_func
ãåŒã³åºãããããšã確èªã§ããŸãã éåæé¢æ°ãå®è¡ããŠã颿°ããã€å®äºããããéç¥ãããã¬ãŒãªã³ã°ãã³ãã©ãŒãäœæããããšãã§ããŸãã æ¬äŒŒã³ãŒãã¯æ¬¡ã®ããã«ãªããŸãã
void on_complete() { ... } void my_func() { ... service.post(on_complete); } async_call(my_func);
async_call
颿°ã¯ãããŸãããç¬èªã«äœæããå¿
èŠããããŸãã 幞ããªããšã«ãããã¯ããã»ã©é£ãããããŸããã æ¬¡ã®ã³ãŒãã¹ãããããåç
§ããŠãã ããã
struct async_op : boost::enable_shared_from_this<async_op>, ... { typedef boost::function<void(boost::system::error_code)> completion_func; typedef boost::function<boost::system::error_code ()> op_func; struct operation { ... }; void start() { { boost::recursive_mutex::scoped_lock lk(cs_); if ( started_) return; started_ = true; } boost::thread t( boost::bind(&async_op::run,this)); } void add(op_func op, completion_func completion, io_service &service) { self_ = shared_from_this(); boost::recursive_mutex::scoped_lock lk(cs_); ops_.push_back( operation(service, op, completion)); if ( !started_) start(); } void stop() { boost::recursive_mutex::scoped_lock lk(cs_); started_ = false; ops_.clear(); } private: boost::recursive_mutex cs_; std::vector<operation> ops_; bool started_; ptr self_; };
async_op
æ§é äœã§ã¯ã远å ïŒ
add()
ïŒãããã¹ãŠã®éåæé¢æ°ã§æ©èœããïŒ
run()
ïŒããã¯ã°ã©ãŠã³ãã¹ã¬ãããäœæãããŸãã ç§ã«ãšã£ãŠãããã¯è€éãªããšã§ã¯ãªãããã§ãããªããªããåæäœã«å¯ŸããŠæ¬¡ã®ããšãå®è¡ãããããã§ãã
- 颿°ã¯éåæã«åŒã³åºãããŸãã
completion
颿°ã¯ã颿°ãæåã«completion
ãããšãã«åŒã³åºãããŸãcompletion
颿°ãå®è¡ããio_service
ã€ã³ã¹ã¿ã³ã¹ã , . :
struct async_op : boost::enable_shared_from_this<async_op> , private boost::noncopyable { struct operation { operation(io_service & service, op_func op, completion_func completion): service(&service), op(op)completion(completion), work(new o_service::work(service)){} operation() : service(0) {} io_service * service; op_func op; completion_func completion; typedef boost::shared_ptr<io_service::work> work_ptr; work_ptr work; }; ... };
, ,
io_service::work
,
service.run()
, ( ,
io_service::work, service.run()
, ). :
struct async_op : ... { typedef boost::shared_ptr<async_op> ptr; static ptr new_() { return ptr(new async_op); } ... void run() { while ( true) { { boost::recursive_mutex::scoped_lock lk(cs_); if ( !started_) break; } boost::this_thread::sleep( boost::posix_time::millisec(10)); operation cur; { boost::recursive_mutex::scoped_lock lk(cs_); if ( !ops_.empty()) { cur = ops_[0]; ops_.erase( ops_.begin()); } } if ( cur.service) cur.service->post(boost::bind(cur.completion, cur.op() )); } self_.reset(); } };
run()
, , ; , . .
,
compute_file_checksum
, :
size_t checksum = 0; boost::system::error_code compute_file_checksum(std::string file_name) { HANDLE file = ::CreateFile(file_name.c_str(), GENERIC_READ, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0); windows::random_access_handle h(service, file); long buff[1024]; checksum = 0; size_t bytes = 0, at = 0; boost::system::error_code ec; while ( (bytes = read_at(h, at, buffer(buff), ec)) > 0) { at += bytes; bytes /= sizeof(long); for ( size_t i = 0; i < bytes; ++i) checksum += buff[i]; } return boost::system::error_code(0, boost::system::generic_category()); } void on_checksum(std::string file_name, boost::system::error_code) { std::cout << "checksum for " << file_name << "=" << checksum << std::endl; } int main(int argc, char* argv[]) { std::string fn = "readme.txt"; async_op::new_()->add( service, boost::bind(compute_file_checksum,fn), boost::bind(on_checksum,fn,_1)); service.run(); }
, . , ,
io_service
, (
post()
) . .
, (, ). , -, .
. , , . , , .

-? , , , . .
, ; ( ), ( ). , , , , , , .
:
- , . , , - .
- , , -:
class proxy : public boost::enable_shared_from_this<proxy> { proxy(ip::tcp::endpoint ep_client, ip::tcp::endpoint ep_server) : ... {} public: static ptr start(ip::tcp::endpoint ep_client, ip::tcp::endpoint ep_svr) { ptr new_(new proxy(ep_client, ep_svr));
ããã¯éåžžã«åçŽãªãããã·ã§ããäž¡ç«¯ã§æ¥ç¶ãããšãäž¡æ¹ã®æ¥ç¶ã§èªã¿åããéå§ããŸãïŒé¢æ°on_start()
ïŒïŒ class proxy : public boost::enable_shared_from_this<proxy> { ... void on_read(ip::tcp::socket & sock, const error_code& err, size_t bytes) { char * buff = &sock == &client_ ? buff_client_ : buff_server_; do_write(&sock == &client_ ? server_ : client_, buff, bytes); } void on_write(ip::tcp::socket & sock, const error_code &err, size_t bytes) { if ( &sock == &client_) do_read(server_, buff_server_); else do_read(client_, buff_client_); } void do_read(ip::tcp::socket & sock, char* buff) { async_read(sock, buffer(buff, max_msg), MEM_FN3(read_complete,ref(sock),_1,_2), MEM_FN3(on_read,ref(sock),_1,_2)); } void do_write(ip::tcp::socket & sock, char * buff, size_t size) { sock.async_write_some(buffer(buff,size), MEM_FN3(on_write,ref(sock),_1,_2)); } size_t read_complete(ip::tcp::socket & sock, const error_code & err, size_t bytes) { if ( sock.available() > 0) return sock.available(); return bytes > 0 ? 0 : 1; } };
èªã¿åããæåãããã³ã«ïŒon_readïŒãã¡ãã»ãŒãžãå察åŽã«æž¡ããŸããã¡ãã»ãŒãžãæ£åžžã«éä¿¡ããããšïŒon_writeïŒãåã³èªã¿åããéå§ããŸãããããæ©èœãããã«ã¯ã次ã®ã³ãŒãã¹ããããã䜿çšããŸãã int main(int argc, char* argv[]) { ip::tcp::endpoint ep_c( ip::address::from_string("127.0.0.1"), 8001); ip::tcp::endpoint ep_s( ip::address::from_string("127.0.0.1"), 8002); proxy::start(ep_c, ep_s); service.run(); }
, (
buff_client_
buff_server_
) . , , . , . , , ( ). , , :
.
ãŸãšã
, , : .
:
Boost.Asio, Boost.Asio â
co-routines
, .
ãã®èšäºã®ãªãœãŒã¹ïŒ
ãªã³ã¯, !