ç§èªèº«ãè·å Žã§ã¯ãlibeventãšlibevãæ€èšããŸããã ããããã«ç¬èªã®å©ç¹ããããŸãã å°ããªhttpãµãŒããŒã®è¿ éãªéçºãå¿ èŠãªå Žåãlibeventã¯ç§ã«ãšã£ãŠéåžžã«èå³ããããC ++ 11ã®é©æ°ã«ãããã³ãŒãã¯ã¯ããã«ã³ã³ãã¯ãã«ãªããåºæ¬çãªhttpãµãŒããŒã40è¡æªæºã§äœæã§ããŸãã
æçš¿ã®å 容ã¯ãããããlibeventã«ãŸã æ £ããŠããªã人ã«ãšã£ãŠæçšã§ãããããã«ç¬èªã®httpãµãŒããŒãäœæããå¿ èŠããããŸãããŸãããã®ãããªè³æã¯ããŸã ãã®ãããªããŒãºãæã£ãŠããªã人ã«ãšã£ãŠãèå³ããããããããŸããã圌ãã®æèŠãšçµéšã æçš¿ã«ã¯æ ¹æ¬çã«æ°ãããã®ãå«ãŸããŠããªãããããã®æ¹åã§äœæ¥ãéå§ããããã®è³æãšããŠäœ¿çšã§ããŸãããããã£ãŠãããã¬ãŒãã³ã°è³æããšããã¡ã¢ãæžããŸãã
libevã®è¯ãç¹ã¯ãããšãã°libevãboost.asioãšã¯ç°ãªããç¬èªã®çµã¿èŸŒã¿HTTPãµãŒããŒãšããããã¡ãŒãæäœããããã®æœè±¡åãããããšã§ãã ãŸããè£å©æ©èœã®ããªãã®ã»ããããããŸãã åçŽãªã¹ããŒããã·ã³ãŸãã¯ä»ã®ã¡ãœãããèšè¿°ããããšã§ãHTTPãããã³ã«ãèªåã§è§£æããããšãã§ããŸãã libeventã䜿çšããå Žåãããã§ãã¹ãŠã§ãã ããã¯ãšãŠãããããšã§ãããŸãã¯ãlibeventã§ãœã±ãããæäœããªãããäžäœã¬ãã«ã«é²ãã§HTTPçšã®ç¬èªã®ããŒãµãŒãäœæã§ããŸãã ã©ã€ãã©ãªã®è©³çŽ°ã¬ãã«ãæ°ã«å ¥ã£ãã®ã¯ãäœãããã°ããå®è¡ãããå Žåãéåžžã¯æè»æ§ã®äœãé«ã¬ãã«ã®ã€ã³ã¿ãŒãã§ã€ã¹ãèŠã€ããããšãã§ããããã§ãã 倧èŠæš¡ãªããŒãºã®åºçŸã«ãããã¬ãã«ãäœããªãã«ã€ããŠã¬ãã«ãåŸã ã«äžããããšãã§ããŸãã ãã®ã©ã€ãã©ãªã䜿çšãããšãéåæå ¥åºåããããã¯ãŒã¯ã®æäœãã¿ã€ããŒã®æäœãrpcãªã©ãå€ãã®ããšãã§ããŸãã ããã䜿çšããŠããµãŒããŒãœãããŠã§ã¢ãšã¯ã©ã€ã¢ã³ããœãããŠã§ã¢ã®äž¡æ¹ãäœæã§ããŸãã
ãªãã§ïŒ
ç¬èªã®å°ããªhttpãµãŒããŒã®äœæã¯ãäœããã®çç±ã§å®å šã«æ©èœããæ¢è£œã®ãµãŒããŒã䜿çšããããšããããŒãºãèŠæããŸãã¯äžæ¬æã«ãã£ãŠããããçºçããå¯èœæ§ããããŸãã ç¬èªã®ãããã³ã«ã«åŸã£ãŠåäœããããã€ãã®åé¡ã解決ãããµãŒããŒãœãããŠã§ã¢ããããHTTPãããã³ã«ãä»ããŠãã®ãœãããŠã§ã¢ã®APIãçºè¡ããå¿ èŠããããšããŸãã ãµãŒããŒãæ§æããHTTPãä»ããŠçŸåšã®ã¹ããŒã¿ã¹ãååŸããããã«äœ¿çšã§ããæ©èœã¯ãããããã§ãã ããšãã°ããã©ã¡ãŒã¿ã䜿çšããŠGETèŠæ±ã®åŠçãæŽçããå¿çãŸãã¯ãã®ä»ã®åœ¢åŒã§å°ããªxmlãæå®ããå Žåã ãã®å ŽåãããããªåŽåã§ç¬èªã®httpãµãŒããŒãäœæã§ããŸããããã¯ãã¡ã€ã³ãµãŒããŒãœãããŠã§ã¢ã®ã€ã³ã¿ãŒãã§ã€ã¹ã«ãªããŸãã ããã«ãç¹å®ã®ãã¡ã€ã«ã»ãããé åžããããã«ç¬èªã®å°èŠæš¡ãªãµãŒãã¹ãäœæããå¿ èŠãããå ŽåããŸãã¯ç¬èªã®Webã¢ããªã±ãŒã·ã§ã³ãäœæããå¿ èŠãããå Žåã¯ããã®ãããªèªäœã®å°èŠæš¡ãµãŒããŒã䜿çšããããšãã§ããŸãã äžè¬çã«ãããã䜿çšããŠèªå·±å®çµåã®ãµãŒããŒãœãããŠã§ã¢ãæ§ç¯ãããã倧èŠæš¡ãªã·ã¹ãã å ã§ãµããŒããµãŒãã¹ãäœæãããã§ããŸãã
40è¡æªæºã®ã·ã³ãã«ãªhttpãµãŒããŒ
libeventã䜿çšããŠåçŽãªã·ã³ã°ã«ã¹ã¬ããHTTPãµãŒããŒãäœæããã«ã¯ã次ã®ããã€ãã®ç°¡åãªæé ã«åŸãå¿ èŠããããŸãã
- event_inité¢æ°ã䜿çšããŠãã°ããŒãã«ã©ã€ãã©ãªãªããžã§ã¯ããåæåããŸãã ãã®é¢æ°ã¯ãã·ã³ã°ã«ã¹ã¬ããåŠçã«ã®ã¿äœ¿çšã§ããŸãã ãã«ãã¹ã¬ããã®äœæ¥ã§ã¯ãã¹ã¬ããããšã«ãªããžã§ã¯ããäœæããå¿ èŠããããŸãïŒããã«ã€ããŠã¯åŸã§è©³ãã説æããŸãïŒã
- httpãµãŒããŒèªäœã®äœæã¯ãã°ããŒãã«ã€ãã³ãåŠçãªããžã§ã¯ããåããã·ã³ã°ã«ã¹ã¬ãããµãŒããŒã®å Žåãevhttp_starté¢æ°ã«ãã£ãŠå®è¡ãããŸãã æåŸã«evhttp_startã§äœæããããªããžã§ã¯ãã¯ãevhttp_freeã§åé€ããå¿ èŠããããŸãã
- çä¿¡èŠæ±ã«å¿çããã«ã¯ãevhttp_set_gencbã䜿çšããŠã³ãŒã«ããã¯é¢æ°ãèšå®ããå¿ èŠããããŸãã
- ãã®åŸãevent_dispatché¢æ°ã䜿çšããŠã€ãã³ãã«ãŒããéå§ã§ããŸãã ãã®é¢æ°ã¯ãã°ããŒãã«ãªããžã§ã¯ããæã€åäžã®ã¹ã¬ããã§åäœããããã«ãèšèšãããŠããŸãã
- èŠæ±ãåŠçãããšããevhttp_request_get_output_bufferé¢æ°ã䜿çšããŠå¿ççšã®ãããã¡ãŒãååŸã§ããŸãã ãã®ãããã¡ã«ã³ã³ãã³ããè¿œå ããŸãã ããšãã°ãevbuffer_add_printfé¢æ°ã䜿çšããŠæååãéä¿¡ããevbuffer_add_fileã䜿çšããŠãã¡ã€ã«ãéä¿¡ã§ããŸãã ãã®åŸãèŠæ±ã«å¯Ÿããå¿çãéä¿¡ããå¿ èŠããããŸããããã¯ãevhttp_send_replyã䜿çšããŠå®è¡ã§ããŸãã
40è¡æªæºã®ã·ã³ã°ã«ã¹ã¬ãããµãŒããŒã³ãŒãïŒ
#include <memory> #include <cstdint> #include <iostream> #include <evhttp.h> int main() { if (!event_init()) { std::cerr << "Failed to init libevent." << std::endl; return -1; } char const SrvAddress[] = "127.0.0.1"; std::uint16_t SrvPort = 5555; std::unique_ptr<evhttp, decltype(&evhttp_free)> Server(evhttp_start(SrvAddress, SrvPort), &evhttp_free); if (!Server) { std::cerr << "Failed to init http server." << std::endl; return -1; } void (*OnReq)(evhttp_request *req, void *) = [] (evhttp_request *req, void *) { auto *OutBuf = evhttp_request_get_output_buffer(req); if (!OutBuf) return; evbuffer_add_printf(OutBuf, "<html><body><center><h1>Hello Wotld!</h1></center></body></html>"); evhttp_send_reply(req, HTTP_OK, "", OutBuf); }; evhttp_set_gencb(Server.get(), OnReq, nullptr); if (event_dispatch() == -1) { std::cerr << "Failed to run messahe loop." << std::endl; return -1; } return 0; }
HTTPãªã¯ãšã¹ããåŠçã§ããæååãHello Worldããè¿ãããšãã§ãã40è¡æªæºã§ããããšãå€æããevbuffer_add_printfé¢æ°ãevbuffer_add_fileã«çœ®ãæãããšããã¡ã€ã«ãéä¿¡ã§ããŸãã ãã®ãµãŒããŒãåºæ¬æ§æãšåŒã¶ããšãã§ããŸãã ã»ãšãã©ã®å Žåãèªåè»ãã£ãŒã©ãŒãäžåç£æ¥è ã¯ãã©ã®ãããªç¶æ³ã«ãããŠããè¿œå ã®ãªãã·ã§ã³ãããå Žåã«éããèªåã®è»ãã¢ããŒãã決ããŠæšæºãšããŠåæ¢ããªãããšã倢èŠãŠããŸãã ãããããã®ãããªãªãã·ã§ã³ãæ¶è²»è ã«å¿ èŠãã©ããããããŠã©ã®çšåºŠãŸã§...
ãã®ãããªåºæ¬çãªããã©ãŒãã³ã¹ããã±ãŒãžãæäŸã§ãããã®ã¯ããã©ã¡ãŒã¿ããããã«ç°ãªã* nixã·ã¹ãã ã®abãŠãŒãã£ãªãã£ã䜿çšããŠç¢ºèªã§ããŸãã
ab -c 1000 -k -r -t 10 httpïŒ//127.0.0.1âº555 /
ãµãŒããŒãœãããŠã§ã¢ïŒ
ãµãŒããŒã®ãã¹ãåïŒ127.0.0.1
ãµãŒããŒããŒãïŒ5555
ããã¥ã¡ã³ããã¹ïŒ/
ããã¥ã¡ã³ãã®é·ãïŒ64ãã€ã
åæå®è¡ã¬ãã«ïŒ1000
ãã¹ãã«ããã£ãæéïŒ2.289ç§
å®å šãªãªã¯ãšã¹ãïŒ50,000
倱æãããªã¯ãšã¹ãïŒ0
æžã蟌ã¿ãšã©ãŒïŒ0
ããŒãã¢ã©ã€ããªã¯ãšã¹ãïŒ50,000
転éãããåèšïŒ8500000ãã€ã
転éãããHTMLïŒ3200000ãã€ã
1ç§ãããã®ãªã¯ãšã¹ãïŒ21843.76 [ïŒ/ç§]ïŒå¹³åïŒ
ãªã¯ãšã¹ããããã®æéïŒ45.780 [ms]ïŒå¹³åïŒ
ãªã¯ãšã¹ããããã®æéïŒ0.046 [ms]ïŒå¹³åããã¹ãŠã®åæãªã¯ãšã¹ãå šäœïŒ
転éé床ïŒ3626.41 [Kãã€ã/ç§]åä¿¡
æ¥ç¶æéïŒããªç§ïŒ
æå°å¹³å[±sd]æ倧äžå€®å€
æ¥ç¶ïŒ0 3 48.6 0 1001
åŠçäžïŒ17 42 9.0 43 93
åŸ æ©äžïŒ17 42 9.0 43 93
åèšïŒ19 45 49.7 43 1053
ãµãŒããŒã®ãã¹ãåïŒ127.0.0.1
ãµãŒããŒããŒãïŒ5555
ããã¥ã¡ã³ããã¹ïŒ/
ããã¥ã¡ã³ãã®é·ãïŒ64ãã€ã
åæå®è¡ã¬ãã«ïŒ1000
ãã¹ãã«ããã£ãæéïŒ2.289ç§
å®å šãªãªã¯ãšã¹ãïŒ50,000
倱æãããªã¯ãšã¹ãïŒ0
æžã蟌ã¿ãšã©ãŒïŒ0
ããŒãã¢ã©ã€ããªã¯ãšã¹ãïŒ50,000
転éãããåèšïŒ8500000ãã€ã
転éãããHTMLïŒ3200000ãã€ã
1ç§ãããã®ãªã¯ãšã¹ãïŒ21843.76 [ïŒ/ç§]ïŒå¹³åïŒ
ãªã¯ãšã¹ããããã®æéïŒ45.780 [ms]ïŒå¹³åïŒ
ãªã¯ãšã¹ããããã®æéïŒ0.046 [ms]ïŒå¹³åããã¹ãŠã®åæãªã¯ãšã¹ãå šäœïŒ
転éé床ïŒ3626.41 [Kãã€ã/ç§]åä¿¡
æ¥ç¶æéïŒããªç§ïŒ
æå°å¹³å[±sd]æ倧äžå€®å€
æ¥ç¶ïŒ0 3 48.6 0 1001
åŠçäžïŒ17 42 9.0 43 93
åŸ æ©äžïŒ17 42 9.0 43 93
åèšïŒ19 45 49.7 43 1053
ab -c 1000 -r -t 10 httpïŒ//127.0.0.1â555/
ãµãŒããŒãœãããŠã§ã¢ïŒ
ãµãŒããŒã®ãã¹ãåïŒ127.0.0.1
ãµãŒããŒããŒãïŒ5555
ããã¥ã¡ã³ããã¹ïŒ/
ããã¥ã¡ã³ãã®é·ãïŒ64ãã€ã
åæå®è¡ã¬ãã«ïŒ1000
ãã¹ãã«ããã£ãæéïŒ5.004ç§
å®å šãªãªã¯ãšã¹ãïŒ50,000
倱æãããªã¯ãšã¹ãïŒ0
æžã蟌ã¿ãšã©ãŒïŒ0
転éãããåèšïŒ6,300,000ãã€ã
転éãããHTMLïŒ3200000ãã€ã
1ç§ãããã®ãªã¯ãšã¹ãïŒ9992.34 [ïŒ/ sec]ïŒå¹³åïŒ
ãªã¯ãšã¹ããããã®æéïŒ100.077 [ms]ïŒå¹³åïŒ
ãªã¯ãšã¹ããããã®æéïŒ0.100 [ms]ïŒå¹³åããã¹ãŠã®åæãªã¯ãšã¹ãå šäœïŒ
転éé床ïŒ1229.53 [Kãã€ã/ç§]åä¿¡
æ¥ç¶æéïŒããªç§ïŒ
æå°å¹³å[±sd]æ倧äžå€®å€
æ¥ç¶ïŒ0 61 214.1 20 3028
åŠçïŒ7 34 17.6 31 277
åŸ æ©äžïŒ6 28 16.9 25 267
åèšïŒ17 95 219.5 50 3055
ãµãŒããŒã®ãã¹ãåïŒ127.0.0.1
ãµãŒããŒããŒãïŒ5555
ããã¥ã¡ã³ããã¹ïŒ/
ããã¥ã¡ã³ãã®é·ãïŒ64ãã€ã
åæå®è¡ã¬ãã«ïŒ1000
ãã¹ãã«ããã£ãæéïŒ5.004ç§
å®å šãªãªã¯ãšã¹ãïŒ50,000
倱æãããªã¯ãšã¹ãïŒ0
æžã蟌ã¿ãšã©ãŒïŒ0
転éãããåèšïŒ6,300,000ãã€ã
転éãããHTMLïŒ3200000ãã€ã
1ç§ãããã®ãªã¯ãšã¹ãïŒ9992.34 [ïŒ/ sec]ïŒå¹³åïŒ
ãªã¯ãšã¹ããããã®æéïŒ100.077 [ms]ïŒå¹³åïŒ
ãªã¯ãšã¹ããããã®æéïŒ0.100 [ms]ïŒå¹³åããã¹ãŠã®åæãªã¯ãšã¹ãå šäœïŒ
転éé床ïŒ1229.53 [Kãã€ã/ç§]åä¿¡
æ¥ç¶æéïŒããªç§ïŒ
æå°å¹³å[±sd]æ倧äžå€®å€
æ¥ç¶ïŒ0 61 214.1 20 3028
åŠçïŒ7 34 17.6 31 277
åŸ æ©äžïŒ6 28 16.9 25 267
åèšïŒ17 95 219.5 50 3055
ãã®ãã¹ãã¯ã32ãããUbuntu 12.10ãªãã¬ãŒãã£ã³ã°ã·ã¹ãã ãå®è¡ããŠããããã»ã©æ°ããã©ãããããïŒ2ã³ã¢ã4 GBã®RAMïŒã§å®è¡ãããŸããã
ãã«ãã¹ã¬ããHTTPãµãŒããŒ
ãã«ãã¹ã¬ããã¯å¿ èŠã§ããïŒ è³ªåã¯ä¿®èŸçã§ã...ãã¹ãŠã®IOã1ã€ã®ã¹ã¬ããã«æŽçãããªã¯ãšã¹ãããã¥ãŒã«å ¥ããŠè€æ°ã®ã¹ã¬ããã«ã¹ã¯ãŒãã§ããŸãã ãã®å Žåãäžèšã®ãµãŒããŒã«ã¯ãåŠççšã®ãã¥ãŒãšã¹ã¬ããã®ããŒã«ãè¿œå ããã ãã§ãããä»ã«ã¯äœããã§ã³ã¹ããªãã§ãã ããã ãã«ãã¹ã¬ãããµãŒããŒãæ§ç¯ããããšããèŠæãããå Žåã以åã®ãµãŒããŒãããå°ãé·ããªããŸãããããã»ã©é·ãã¯ãªããŸããã äžèšã®äŸã®std :: unique_ptrã§ç€ºãããããã«ãã¹ããŒããã€ã³ã¿ãŒãåããC ++ 11ã§ã¯RAIIãé©åã«å®è£ ã§ããã©ã ãé¢æ°ã®ååšã«ããã³ãŒãããããã«åæžãããŸãã
ãã«ãã¹ã¬ãããµãŒããŒã®äŸã¯ããã®ã€ããªãã®ãŒãã·ã³ã°ã«ã¹ã¬ãããµãŒããŒã«äŒŒãŠããããã«ãã¹ã¬ããã«é¢é£ããäžéšã®æ©èœã¯ã³ãŒãéã®çŽ2åå¢å ããŸãã C ++ã§ã®ãã«ãã¹ã¬ããhttpãµãŒããŒçšã®æ°è¡ã®ã³ãŒãã§80ã¯ããã»ã©å€ããããŸããã
äœæã§ãã1ã€ã®ãœãªã¥ãŒã·ã§ã³ïŒ
- ããšãã°ãããã»ããµã³ã¢ã®æ°ã®2åã«çããè€æ°ã®ã¹ã¬ãããäœæããŸãã C ++ 11ã¯ã¹ã¬ããã®æäœããµããŒãããŠãããç¬èªã®ã©ãããŒãèšè¿°ããå¿ èŠã¯ãªããªããŸããã
- ã¹ã¬ããããšã«ãevent_base_newé¢æ°ã䜿çšããŠç¬èªã®ã€ãã³ãåŠçãªããžã§ã¯ããäœæããŸãã æåŸã«äœæããããªããžã§ã¯ãã¯event_base_freeé¢æ°ã«ãã£ãŠåé€ããå¿ èŠããããstd :: unique_ptrããã³RAIIã«ããããããããã³ã³ãã¯ãã«è¡ãããšãã§ããŸãã
- äžèšã®ãªããžã§ã¯ããèæ ®ããŠãã¹ããªãŒã ããšã«ãevhttp_newé¢æ°ã䜿çšããŠç¬èªã®http-serverãªããžã§ã¯ããäœæããŸãã ãã®ãªããžã§ã¯ããæåŸã«åé€ããå¿ èŠããããŸããããã¯ãevhttp_freeã䜿çšããŠå®è¡ã§ããŸãã
- åã®äŸã®ããã«ãevhttp_set_gencbã䜿çšããŠèŠæ±ãã³ãã©ãŒãã€ã³ã¹ããŒã«ããŸãã
- ãã®æé ã¯æãå¥åŠãªå ŽåããããŸãã ãœã±ãããäœæããŠããããããç¬èªã®ã¹ã¬ããã«é 眮ãããŠããè€æ°ã®ãã³ãã©ãŒã®ãããã¯ãŒã¯ã€ã³ã¿ãŒãã§ã€ã¹ã«ãã€ã³ãããå¿ èŠããããŸãã ããã§ãAPIã䜿çšããŠãœã±ãããæäœïŒãœã±ãããäœæãæ§æãç¹å®ã®ã€ã³ã¿ãŒãã§ã€ã¹ã«ãã€ã³ãïŒããŠãããevhttp_accept_socketé¢æ°ã䜿çšããŠæäœçšã®ãœã±ããããµãŒããŒã«æž¡ãããšãã§ããŸãã ããã¯é·ãæéã§ãã Libeventã¯ããã®åé¡ã解決ããããã®ããã€ãã®æ©èœãæäŸããŸãã åè¿°ã®ããã«ãlibeventã䜿çšãããšãå¿ èŠã«å¿ããŠã¬ãã«ãäžããããå¿ èŠã«å¿ããŠæé©ãªã¬ãã«ãéžæãããã§ããŸãã ãã®å Žåãæåã®ã¹ã¬ããã§ã¯ããœã±ããã®äœæããã®æ§æãšãã€ã³ãã®ãã¹ãŠã®äœæ¥ã¯evhttp_bind_socket_with_handleé¢æ°ã«ãã£ãŠå®è¡ãããä»ã®ãããŒã®ãœã±ããã¯evhttp_bound_socket_get_fdã䜿çšããŠæ§ææžã¿ãªããžã§ã¯ãããæœåºãããŸãã ä»ã®ãã¹ãŠã®ã¹ã¬ããã¯æ¢ã«åä¿¡ãããœã±ããã䜿çšããŠãããevhttp_accept_socketé¢æ°ã«ããåŠççšã«èšå®ããŠããŸãã å°ãå¥åŠã§ããããœã±ãããæäœããããã«APIã䜿çšãããããã¯ããã«ç°¡åã§ãã¯ãã¹ãã©ãããã©ãŒã ãæ€èšããå Žåã¯ããã«ç°¡åã§ãã Berkeleyãœã±ããã®APIã¯åãããã«èŠããŸãããããšãã°WindowsãLinuxåãã«ã¯ãã¹ãã©ãããã©ãŒã ãœãããŠã§ã¢ã䜿çšããŠäœæããå Žåããããªãã¬ãŒãã£ã³ã°ã·ã¹ãã çšã«èšè¿°ãããã³ãŒãã¯ãå¥ã®ãªãã¬ãŒãã£ã³ã°ã·ã¹ãã çšã®ã³ãŒããšã¯ãŸã£ããç°ãªããŸãã
- ã€ãã³ãã«ãŒããéå§ããŸãã ã·ã³ã°ã«ã¹ã¬ãããµãŒããŒãšã¯ç°ãªããããã¯å¥ã®æ¹æ³ã§è¡ãå¿ èŠããããŸãã誰ããç°ãªããªããžã§ã¯ããæã£ãŠããããã§ãã libeventïŒevent_base_dispatchïŒã«ã¯ãã®ããã®ç¹å¥ãªæ©èœããããŸãã ç§ã«ãšã£ãŠã¯ããã€ãã¹ã1ã€ãããŸããæ£ããæ¹æ³ã§ä¿®æ£ããããšã¯å°é£ã§ãïŒããšãã°ãevent_base_loopexitãåŒã³åºãããšãã§ããç¶æ³ãå¿ èŠãªå ŽåïŒã ãããè¡ãã«ã¯ãå°ããããå¿ èŠããããŸãã ãããã£ãŠãé¢æ°event_base_loopã䜿çšã§ããŸãã ãã®é¢æ°ã¯ãåŠçããã€ãã³ãããªããŠããããã¯ãããå¶åŸ¡ãè¿ããŸããããã«ãããã€ãã³ãåŠçãµã€ã¯ã«ãå®äºããç°¡åãªæ©äŒãšãåŒã³åºãéã§äœããè¡ãæ©èœãæäŸãããŸãã ãã€ãã¹ããããŸã-ããã»ããµãç¡é§ã«äœ¿çšããªãããã«ãå°ãªããšãããããªé 延ãèšå®ããå¿ èŠããããŸãïŒC ++ 11ã§ã¯-std :: this_thread :: sleep_forïŒstd :: chrono :: millisecondsïŒ10ïŒïŒ ïŒ
- èŠæ±åŠçã¯æåã®äŸã«äŒŒãŠããŸãã
- 次ã®ã¹ã¬ããã®äœæããã³æ§æäžã«ããã®æ©èœã«åé¡ãããå¯èœæ§ããããŸããããšãã°ãäžéšã®libeventé¢æ°ããšã©ãŒãå ±åããŸããã ãã®å ŽåãäŸå€ãã¹ããŒããŠãã£ããããåãC ++ 11ããŒã«ïŒstd :: exception_ptrãstd :: current_exceptionããã³std :: rethrow_exceptionïŒã䜿çšããŠã¹ããªãŒã ã®å€éšã«éä¿¡ã§ããŸãã
ã·ã³ãã«ãªãã«ãã¹ã¬ãããµãŒããŒã³ãŒãïŒ
#include <stdexcept> #include <iostream> #include <memory> #include <chrono> #include <thread> #include <cstdint> #include <vector> #include <evhttp.h> int main() { char const SrvAddress[] = "127.0.0.1"; std::uint16_t const SrvPort = 5555; int const SrvThreadCount = 4; try { void (*OnRequest)(evhttp_request *, void *) = [] (evhttp_request *req, void *) { auto *OutBuf = evhttp_request_get_output_buffer(req); if (!OutBuf) return; evbuffer_add_printf(OutBuf, "<html><body><center><h1>Hello Wotld!</h1></center></body></html>"); evhttp_send_reply(req, HTTP_OK, "", OutBuf); }; std::exception_ptr InitExcept; bool volatile IsRun = true; evutil_socket_t Socket = -1; auto ThreadFunc = [&] () { try { std::unique_ptr<event_base, decltype(&event_base_free)> EventBase(event_base_new(), &event_base_free); if (!EventBase) throw std::runtime_error("Failed to create new base_event."); std::unique_ptr<evhttp, decltype(&evhttp_free)> EvHttp(evhttp_new(EventBase.get()), &evhttp_free); if (!EvHttp) throw std::runtime_error("Failed to create new evhttp."); evhttp_set_gencb(EvHttp.get(), OnRequest, nullptr); if (Socket == -1) { auto *BoundSock = evhttp_bind_socket_with_handle(EvHttp.get(), SrvAddress, SrvPort); if (!BoundSock) throw std::runtime_error("Failed to bind server socket."); if ((Socket = evhttp_bound_socket_get_fd(BoundSock)) == -1) throw std::runtime_error("Failed to get server socket for next instance."); } else { if (evhttp_accept_socket(EvHttp.get(), Socket) == -1) throw std::runtime_error("Failed to bind server socket for new instance."); } for ( ; IsRun ; ) { event_base_loop(EventBase.get(), EVLOOP_NONBLOCK); std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } catch (...) { InitExcept = std::current_exception(); } }; auto ThreadDeleter = [&] (std::thread *t) { IsRun = false; t->join(); delete t; }; typedef std::unique_ptr<std::thread, decltype(ThreadDeleter)> ThreadPtr; typedef std::vector<ThreadPtr> ThreadPool; ThreadPool Threads; for (int i = 0 ; i < SrvThreadCount ; ++i) { ThreadPtr Thread(new std::thread(ThreadFunc), ThreadDeleter); std::this_thread::sleep_for(std::chrono::milliseconds(500)); if (InitExcept != std::exception_ptr()) { IsRun = false; std::rethrow_exception(InitExcept); } Threads.push_back(std::move(Thread)); } std::cout << "Press Enter fot quit." << std::endl; std::cin.get(); IsRun = false; } catch (std::exception const &e) { std::cerr << "Error: " << e.what() << std::endl; } return 0; }
ã³ãŒãã§ã¯ãåã¹ã¬ããããã°ããåŸ ã£ãŠããäœæãããŠããããšãããããŸãã ããã¯ããµãŒããŒã®æçµããŒãžã§ã³ã§ãã§ã«ä¿®æ£ãããå°ããªããã¯ã§ãã çŸæç¹ã§ã¯ããããè¡ãããªãå Žåãã¹ã¬ãããäœããã®æ¹æ³ã§åæããå¿ èŠããããšããèšããªãããããœã±ãããäœæããŠãã€ã³ãããããã®ãå¥åŠãªã¹ããããã解決ããŸãã ç°¡åã«ããããã«ããã®ããã¯ã¯ãã®ãŸãŸã«ããŠãããŸãã ãŸããäžèšã®ã³ãŒãã§ã¯ãã©ã ãé¢æ°ã¯ç©è°ãéžã解決çã®ããã«èŠãããããããŸããã ã©ã ãã¯ãããšãã°ãæšæºã¢ã«ãŽãªãºã ã䜿çšããå Žåã®ããçš®ã®è¿°èªãšããŠäœ¿çšãããšãåªãããœãªã¥ãŒã·ã§ã³ã«ãªããŸãã åæã«ããã倧ããªã³ãŒããæžããšãã®äœ¿çšã«ã€ããŠèããããšãã§ããŸãã äžèšã®äŸã§ã¯ããã¹ãŠãéåžžã®é¢æ°ã«å ¥ããå¿ èŠãªãã¹ãŠã®ãã©ã¡ãŒã¿ãŒãæž¡ããC ++ 03ã¹ã¿ã€ã«ã®ã³ãŒããååŸã§ããŸãã åæã«ãã©ã ãã®äœ¿çšã«ããã³ãŒãã®éãåæžãããŸããã ç§ã®æèŠã§ã¯ãã³ãŒããå°ããå Žåãã©ã ãã¯æçã®ã³ã³ãã³ãã§ã¯ãªããã³ãŒãã®å質ã«æªåœ±é¿ãäžããªãå Žåã§ãéåžžã«ããŸãé©åããããšãã§ããŸããäž»ãªæ©èœã
åã®äŸãšåããã©ã¡ãŒã¿ãŒã䜿çšããŠããã«ãã¹ã¬ãããµãŒããŒã®ãã¹ããå®è¡ããŸããã
ab -c 1000 -k -r -t 10 httpïŒ//127.0.0.1âº555 /
ãµãŒããŒãœãããŠã§ã¢ïŒ
ãµãŒããŒã®ãã¹ãåïŒ127.0.0.1
ãµãŒããŒããŒãïŒ5555
ããã¥ã¡ã³ããã¹ïŒ/
ããã¥ã¡ã³ãã®é·ãïŒ64ãã€ã
åæå®è¡ã¬ãã«ïŒ1000
ãã¹ãã«ããã£ãæéïŒ1.576ç§
å®å šãªãªã¯ãšã¹ãïŒ50,000
倱æãããªã¯ãšã¹ãïŒ0
æžã蟌ã¿ãšã©ãŒïŒ0
ããŒãã¢ã©ã€ããªã¯ãšã¹ãïŒ50,000
転éãããåèšïŒ8500000ãã€ã
転éãããHTMLïŒ3200000ãã€ã
1ç§ãããã®ãªã¯ãšã¹ãïŒ31717.96 [ïŒ/ sec]ïŒå¹³åïŒ
ãªã¯ãšã¹ããããã®æéïŒ31.528 [ms]ïŒå¹³åïŒ
ãªã¯ãšã¹ãããšã®æéïŒ0.032 [ms]ïŒå¹³åããã¹ãŠã®åæãªã¯ãšã¹ãå šäœïŒ
転éé床ïŒ5265.68 [Kãã€ã/ç§]åä¿¡
ãµãŒããŒã®ãã¹ãåïŒ127.0.0.1
ãµãŒããŒããŒãïŒ5555
ããã¥ã¡ã³ããã¹ïŒ/
ããã¥ã¡ã³ãã®é·ãïŒ64ãã€ã
åæå®è¡ã¬ãã«ïŒ1000
ãã¹ãã«ããã£ãæéïŒ1.576ç§
å®å šãªãªã¯ãšã¹ãïŒ50,000
倱æãããªã¯ãšã¹ãïŒ0
æžã蟌ã¿ãšã©ãŒïŒ0
ããŒãã¢ã©ã€ããªã¯ãšã¹ãïŒ50,000
転éãããåèšïŒ8500000ãã€ã
転éãããHTMLïŒ3200000ãã€ã
1ç§ãããã®ãªã¯ãšã¹ãïŒ31717.96 [ïŒ/ sec]ïŒå¹³åïŒ
ãªã¯ãšã¹ããããã®æéïŒ31.528 [ms]ïŒå¹³åïŒ
ãªã¯ãšã¹ãããšã®æéïŒ0.032 [ms]ïŒå¹³åããã¹ãŠã®åæãªã¯ãšã¹ãå šäœïŒ
転éé床ïŒ5265.68 [Kãã€ã/ç§]åä¿¡
ab -c 1000 -r -t 10 httpïŒ//127.0.0.1â555/
ãµãŒããŒãœãããŠã§ã¢ïŒ
ãµãŒããŒã®ãã¹ãåïŒ127.0.0.1
ãµãŒããŒããŒãïŒ5555
ããã¥ã¡ã³ããã¹ïŒ/
ããã¥ã¡ã³ãã®é·ãïŒ64ãã€ã
åæå®è¡ã¬ãã«ïŒ1000
ãã¹ãã«ããã£ãæéïŒ3.685ç§
å®å šãªãªã¯ãšã¹ãïŒ50,000
倱æãããªã¯ãšã¹ãïŒ0
æžã蟌ã¿ãšã©ãŒïŒ0
転éãããåèšïŒ6,300,000ãã€ã
転éãããHTMLïŒ3200000ãã€ã
1ç§ãããã®ãªã¯ãšã¹ãæ°ïŒ13568.41 [ïŒ/ sec]ïŒå¹³åïŒ
ãªã¯ãšã¹ããããã®æéïŒ73.701 [ms]ïŒå¹³åïŒ
ãªã¯ãšã¹ããããã®æéïŒ0.074 [ms]ïŒå¹³åããã¹ãŠã®åæãªã¯ãšã¹ãå šäœïŒ
転éé床ïŒ1669.55 [Kãã€ã/ç§]åä¿¡
æ¥ç¶æéïŒããªç§ïŒ
æå°å¹³å[±sd]æ倧äžå€®å€
æ¥ç¶ïŒ0 36 117.2 23 1033
åŠçäžïŒ3 37 10.0 37 247
åŸ æ©äžïŒ3 30 8.7 30 242
åèšïŒ9 73 118.8 61 1089
ãµãŒããŒã®ãã¹ãåïŒ127.0.0.1
ãµãŒããŒããŒãïŒ5555
ããã¥ã¡ã³ããã¹ïŒ/
ããã¥ã¡ã³ãã®é·ãïŒ64ãã€ã
åæå®è¡ã¬ãã«ïŒ1000
ãã¹ãã«ããã£ãæéïŒ3.685ç§
å®å šãªãªã¯ãšã¹ãïŒ50,000
倱æãããªã¯ãšã¹ãïŒ0
æžã蟌ã¿ãšã©ãŒïŒ0
転éãããåèšïŒ6,300,000ãã€ã
転éãããHTMLïŒ3200000ãã€ã
1ç§ãããã®ãªã¯ãšã¹ãæ°ïŒ13568.41 [ïŒ/ sec]ïŒå¹³åïŒ
ãªã¯ãšã¹ããããã®æéïŒ73.701 [ms]ïŒå¹³åïŒ
ãªã¯ãšã¹ããããã®æéïŒ0.074 [ms]ïŒå¹³åããã¹ãŠã®åæãªã¯ãšã¹ãå šäœïŒ
転éé床ïŒ1669.55 [Kãã€ã/ç§]åä¿¡
æ¥ç¶æéïŒããªç§ïŒ
æå°å¹³å[±sd]æ倧äžå€®å€
æ¥ç¶ïŒ0 36 117.2 23 1033
åŠçäžïŒ3 37 10.0 37 247
åŸ æ©äžïŒ3 30 8.7 30 242
åèšïŒ9 73 118.8 61 1089
ãµãŒããŒã®æçµããŒãžã§ã³
åºæ¬çãªæ©åšãæäŸãããŸããããªãã·ã§ã³ã®å°ããªã»ãããæã€æ©åšããããŸãã ä»åºŠã¯ãå°ããã¥ãŒãã³ã°ãå ããŠãããæçšã§æ©èœçãªãã®ãäœæããçªãåºãŸããã
æå°HTTPãµãŒããŒïŒ
#include "http_server.h" #include "http_headers.h" #include "http_content_type.h" #include <iostream> int main() { try { using namespace Network; HttpServer Srv("127.0.0.1", 5555, 4, [&] (IHttpRequestPtr req) { req->SetResponseAttr(Http::Response::Header::Server::Value, "MyTestServer"); req->SetResponseAttr(Http::Response::Header::ContentType::Value, Http::Content::Type::html::Value); req->SetResponseString("<html><body><center><h1>Hello Wotld!</h1></center></body></html>"); }); std::cout << "Press Enter for quit." << std::endl; std::cin.get(); } catch (std::exception const &e) { std::cout << e.what() << std::endl; } return 0; }
C ++ httpãµãŒããŒã®éåžžã«æå°éã®ã³ãŒãã ãã¹ãŠã«æéãããããŸãã ãããŠããã®å ŽåããµãŒããŒãäœæããããã®ã¯ã©ã€ã¢ã³ãã³ãŒãã®ãã®ãããªåçŽãã¯ãlibeventã®ææ¡ãããã©ãããŒã«é ãããããé·ãå®è£ ã«ãã£ãŠæ¯æãããŸãã å®éã売ãäžãã¯ãããã«å¢å ããŠããŸãã 以äžã«ããã®æçã«ã€ããŠèª¬æããŸãã
ãµãŒããŒã®äœæïŒ
- ã¿ã€ãHttpServerã®ãªããžã§ã¯ããäœæããå¿ èŠããããŸãã å°ãªããšãããµãŒããŒãåäœããã¢ãã¬ã¹ãšããŒããã¹ã¬ããã®æ°ãããã³ãªã¯ãšã¹ããåŠçããããã®é¢æ°ããã©ã¡ãŒã¿ãŒãšããŠæž¡ããŸãïŒãã®å Žåããªã¯ãšã¹ãã®åŠçã¯æå°éã§ãããããå¥åã®é¢æ°ãŸãã¯ãã³ãã©ãŒã¯ã©ã¹å šäœãäœæããã«å°ãã®ã©ã ããå®è¡ã§ããŸãïŒ ã ãªããžã§ã¯ãã®äœæåŸããµãŒããŒã¯ãã®ãªããžã§ã¯ããååšããéãæ©èœããŸãã
- ãã³ãã©ãŒã¯ãIHttpRequestã€ã³ã¿ãŒãã§ã€ã¹ãžã®ã¹ããŒããã€ã³ã¿ãŒãåãå ¥ããŸããIHttpRequestã€ã³ã¿ãŒãã§ã€ã¹ã®å®è£ ã¯ãlibeventãããã¡ãŒã§ã®ãã¹ãŠã®äœæ¥ãé ããå¿çãéä¿¡ããŸãããã®ã¡ãœããã«ãããçä¿¡èŠæ±ããããŒã¿ãåä¿¡ããå¿çã圢æã§ããŸãã
IHttpRequestã€ã³ã¿ãŒãã§ã€ã¹
namespace Network { DECLARE_RUNTIME_EXCEPTION(HttpRequest) struct IHttpRequest { enum class Type { HEAD, GET, PUT, POST }; typedef std::unordered_map<std::string, std::string> RequestParams; virtual ~IHttpRequest() {} virtual Type GetRequestType() const = 0; virtual std::string const GetHeaderAttr(char const *attrName) const = 0; virtual std::size_t GetContentSize() const = 0; virtual void GetContent(void *buf, std::size_t len, bool remove) const = 0; virtual std::string const GetPath() const = 0; virtual RequestParams const GetParams() const = 0; virtual void SetResponseAttr(std::string const &name, std::string const &val) = 0; virtual void SetResponseCode(int code) = 0; virtual void SetResponseString(std::string const &str) = 0; virtual void SetResponseBuf(void const *data, std::size_t bytes) = 0; virtual void SetResponseFile(std::string const &fileName) = 0; }; typedef std::shared_ptr<IHttpRequest> IHttpRequestPtr; }
ãã®ã€ã³ã¿ãŒãã§ã€ã¹ã䜿çšãããšãçä¿¡ãªã¯ãšã¹ãããããã®ã¿ã€ããäžéšã®å±æ§ïŒããããŒïŒããªã¯ãšã¹ãæ¬æã®ãµã€ãºããªã¯ãšã¹ãæ¬æèªäœïŒå©çšå¯èœãªå ŽåïŒãåä¿¡ããå±æ§ïŒããããŒïŒããªã¯ãšã¹ãå®äºã³ãŒããããã³ã¬ã¹ãã³ã¹æ¬æïŒãã®äžã«ïŒå®è£ ã§ã¯ãæååããããã¡ãŸãã¯ãã¡ã€ã«ãå¿çã§æž¡ãããã®ã¡ãœããããããŸãïŒã å®è£ ã®åã¡ãœããã¯ãHttpRequestExceptionåã®äŸå€ãã¹ããŒã§ããŸãã
ãµãŒããŒã³ãŒããããäžåºŠèŠããšããªã¯ãšã¹ãåŠçã³ãŒãã®æ¬¡ã®è¡ã«æ°ä»ãããšãã§ããŸãã
req->SetResponseAttr(Http::Response::Header::Server::Value, "MyTestServer"); req->SetResponseAttr(Http::Response::Header::ContentType::Value, Http::Content::Type::html::Value);
ãããå¿çããããŒã®æ§æã§ããããã®äŸã§ã¯ããContent-TypeãããServerããªã©ã®ããããŒãã£ãŒã«ããèšå®ãããŠããŸãã libeventã«ã¯HTTPã®ããŒãºãã¯ããã«è¶ ããéåžžã«å¹ åºãæ©èœããããšããäºå®ã«ãããããããããããŒã€ãã³ãå®æ°ã®ãªã¹ãã¯ãããŸããã æ»ãã³ãŒãã®ãªã¹ãã¯äžå®å šã§ãïŒæãäžè¬çã«äœ¿çšãããŠããŸãïŒã ããããŒãã£ãŒã«ããå®çŸ©ããæååãæ··ä¹±ãããªãããïŒããšãã°ããŠãŒã¶ãŒã³ãŒãã®ã¿ã€ããã¹ãé¿ããããïŒããã¹ãŠã®å®æ°ã¯libeventã®ææ¡ãããã©ãããŒã§æ¢ã«å®çŸ©ãããŠããŸãã
æååå®æ°ãå®çŸ©ããäŸ
namespace Network { namespace Http { namespace Request { namespace Header { DECLARE_STRING_CONSTANT(Accept, Accept) DECLARE_STRING_CONSTANT(AcceptCharset, Accept-Charset) // ... } } namespace Response { namespace Header { DECLARE_STRING_CONSTANT(AccessControlAllowOrigin, Access-Control-Allow-Origin) DECLARE_STRING_CONSTANT(AcceptRanges, Accept-Ranges) // ... } } } }
æååå®æ°ã¯ãããããŒãã¡ã€ã«å ã®çŽç²ãªCã®å€ãã¹ã¿ã€ã«ã®åçŽãªãã¯ããšããŠå®çŸ©ã§ããŸãããŸãã宣èšãšå®çŸ©ã.hãã¡ã€ã«ãš.cppãã¡ã€ã«ã«åºããªããããã§ã«C ++ã¹ã¿ã€ã«ã§æšæºåãããŠããŸãã ãã ãããã¡ã€ã«ã®ééã空ããã«ãããããŒãã¡ã€ã«ã§ã®ã¿ãã¹ãŠã®åä»ãå®çŸ©ãC ++ã¹ã¿ã€ã«ã§äœæã§ããŸãã ãããè¡ãã«ã¯ããã³ãã¬ãŒãã§äœããã®ã¢ãããŒãã䜿çšãããã®ãããªãã¯ããäœæããŸãïŒãã¡ããããã¯ãã¯C ++ã«ãã£ãŠèªèãããæªæã®ããå°éã®ããŒã ã§ã;ç°çš®ãœãªã¥ãŒã·ã§ã³ã«ã¯ããé«ãå®è¡å¯èœæ§ããããŸãïŒã
DECLARE_STRING_CONSTANT
#define DECLARE_STRING_CONSTANT(name_, value_) \ namespace Private \ { \ template <typename T> \ struct name_ \ { \ static char const Name[]; \ static char const Value[]; \ }; \ template <typename T> \ char const name_ <T>::Name[] = #name_; \ template <typename T> \ char const name_ <T>::Value[] = #value_; \ } \ typedef Private:: name_ <void> name_;
ã»ãšãã©åãããã«ãã³ã³ãã³ãã®ã¿ã€ããèšå®ããããã®å®æ°ãå®çŸ©ãããŠããŸãã ããããªä¿®æ£ãå¿ èŠã§ãã ãªã¯ãšã¹ããžã®å¿çã§ãã¡ã€ã«ãéä¿¡ãããšãã®äŸ¿å®ã®ããã«ããã¡ã€ã«æ¡åŒµåã«ããã³ã³ãã³ãã¿ã€ãã®æ€çŽ¢ãå®è£ ããããšããèŠæããããŸããã
ããšãã°ããªã¯ãšã¹ãããããªãœãŒã¹ãžã®é·ç§»ãè¡ããããã¹ããããŒãžããããŠãŒã¶ãŒãCookieãæã£ãŠãããªã©ãçä¿¡ãªã¯ãšã¹ãããäœããååŸãããå Žåã¯ãçä¿¡ãªã¯ãšã¹ãã®ããããŒãããã®ãã¹ãŠãååŸã§ããŸãã
std::string Host = req->GetHeaderAttr(Http::Request::Header::Host::Value); std::string Referer = req->GetHeaderAttr(Http::Request::Header::Referer::Value); std::string Cookie = req->GetHeaderAttr(Http::Request::Header::Cookie::Value);
åæ§ã«ãå¿çã§ã¯ãããšãã°ããŠãŒã¶ãŒã«ããã€ãã®Cookieãèšå®ã§ããŸããCookieã¯åŸã§ã»ãã·ã§ã³ã§æ©èœãããŠãŒã¶ãŒããªãœãŒã¹ãããŸãããã©ããã远跡ããŸãïŒå¿çããããŒã®äœ¿çšäŸã¯ããµãŒããŒã³ãŒãã«èšèŒãããŠããŸãïŒã
HTTPãä»ããŠAPIã®äžéšãæŽçããå Žåã¯ãåããããç°¡åã§ãã ã¡ãœãããäœæããå¿ èŠããããšããŸãïŒã»ãã·ã§ã³ãéãããµãŒããŒã«é¢ããçµ±èšæ å ±ãååŸããã»ãã·ã§ã³ãéããŸãã ãµãŒããŒãžã®ãã®ã¯ãšãªæååã次ã®ããã«ããŸãã
http://myserver.com/service/login/OpenSession?user=nym&pwd=kakoyto http://myserver.com/service/login/CliseSession?sessionId=nym1234567890 http://myserver.com/service/stat/GetInfo?sessionId=nym1234567890
ãããã®ã¯ãšãªæååã«å¿çããããšã«ããããŠãŒã¶ãŒãµãŒããŒã¯ãããšãã°xml圢åŒã§äœããã®çš®é¡ã®å¿çãçæã§ããŸãã ããã¯ãµãŒããŒéçºè ã®ä»äºã§ãã ãããããã®ãããªãªã¯ãšã¹ããåŠçããæ¹æ³ãããããããã©ã¡ãŒã¿ãååŸããæ¹æ³ã以äžã«ç€ºããŸãã
auto Path = req->GetPath(); auto Params = req->GetParams();
äžèšã®äŸã®æ¹æ³ã®1ã€ã¯/ service / login / OpenSessionã§ããããã©ã¡ãŒã¿ãŒã¯æž¡ãããããŒãšå€ã®ãã¢ã®ãããã§ãã ãã©ã¡ãŒã¿ã«ãŒãã¿ã€ãïŒ
typedef std::unordered_map<std::string, std::string> RequestParams;
libeventäžã®ã©ãããŒã®ææ¡ãããæçµããŒãžã§ã³ã䜿çšããŠå®è£ ã§ãããã¹ãŠãåæããåŸããã®ã©ãããŒèªäœã®å éšã確èªã§ããŸãã
ã¯ã©ã¹HttpServer
namespace Network { DECLARE_RUNTIME_EXCEPTION(HttpServer) class HttpServer final : private Common::NonCopyable { public: typedef std::vector<IHttpRequest::Type> MethodPool; typedef std::function<void (IHttpRequestPtr)> OnRequestFunc; enum { MaxHeaderSize = static_cast<std::size_t>(-1), MaxBodySize = MaxHeaderSize }; HttpServer(std::string const &address, std::uint16_t port, std::uint16_t threadCount, OnRequestFunc const &onRequest, MethodPool const &allowedMethods = {IHttpRequest::Type::GET }, std::size_t maxHeadersSize = MaxHeaderSize, std::size_t maxBodySize = MaxBodySize); private: volatile bool IsRun = true; void (*ThreadDeleter)(std::thread *t) = [] (std::thread *t) { t->join(); delete t; };; typedef std::unique_ptr<std::thread, decltype(ThreadDeleter)> ThreadPtr; typedef std::vector<ThreadPtr> ThreadPool; ThreadPool Threads; Common::BoolFlagInvertor RunFlag; }; } </source</spoiler> <spoiler title=" HttpServer"><source lang="cpp"> namespace Network { HttpServer::HttpServer(std::string const &address, std::uint16_t port, std::uint16_t threadCount, OnRequestFunc const &onRequest, MethodPool const &allowedMethods, std::size_t maxHeadersSize, std::size_t maxBodySize) : RunFlag(&IsRun) { int AllowedMethods = -1; for (auto const i : allowedMethods) AllowedMethods |= HttpRequestTypeToAllowedMethod(i); bool volatile DoneInitThread = false; std::exception_ptr Except; evutil_socket_t Socket = -1; auto ThreadFunc = [&] () { try { bool volatile ProcessRequest = false; RequestParams ReqPrm; ReqPrm.Func = onRequest; ReqPrm.Process = &ProcessRequest; typedef std::unique_ptr<event_base, decltype(&event_base_free)> EventBasePtr; EventBasePtr EventBase(event_base_new(), &event_base_free); if (!EventBase) throw HttpServerException("Failed to create new base_event."); typedef std::unique_ptr<evhttp, decltype(&evhttp_free)> EvHttpPtr; EvHttpPtr EvHttp(evhttp_new(EventBase.get()), &evhttp_free); if (!EvHttp) throw HttpServerException("Failed to create new evhttp."); evhttp_set_allowed_methods(EvHttp.get(), AllowedMethods); if (maxHeadersSize != MaxHeaderSize) evhttp_set_max_headers_size(EvHttp.get(), maxHeadersSize); if (maxBodySize != MaxBodySize) evhttp_set_max_body_size(EvHttp.get(), maxBodySize); evhttp_set_gencb(EvHttp.get(), &OnRawRequest, &ReqPrm); if (Socket == -1) { auto *BoundSock = evhttp_bind_socket_with_handle(EvHttp.get(), address.c_str(), port); if (!BoundSock) throw HttpServerException("Failed to bind server socket."); if ((Socket = evhttp_bound_socket_get_fd(BoundSock)) == -1) throw HttpServerException("Failed to get server socket for next instance."); } else { if (evhttp_accept_socket(EvHttp.get(), Socket) == -1) throw HttpServerException("Failed to bind server socket for new instance."); } DoneInitThread = true; for ( ; IsRun ; ) { ProcessRequest = false; event_base_loop(EventBase.get(), EVLOOP_NONBLOCK); if (!ProcessRequest) std::this_thread::sleep_for(std::chrono::milliseconds(100)); } } catch (...) { Except = std::current_exception(); } }; ThreadPool NewThreads; for (int i = 0 ; i < threadCount ; ++i) { DoneInitThread = false; ThreadPtr Thread(new std::thread(ThreadFunc), ThreadDeleter); NewThreads.push_back(std::move(Thread)); for ( ; ; ) { if (Except != std::exception_ptr()) { IsRun = false; std::rethrow_exception(Except); } if (DoneInitThread) break; std::this_thread::sleep_for(std::chrono::milliseconds(100)); } } Threads = std::move(NewThreads); } }
ã¯ãšãªåŠçæ©èœã¯ããµã³ãã«ã®ãœãŒã¹ãã¡ã€ã«ãããŠã³ããŒãããããšã§ãã«ããŒãžã§ã³ã§è¡šç€ºã§ããŸãã以åã®ãµã³ãã«ãããå°ãå€ããªããã³ãŒãã®å¯èªæ§ãæãªãããšãªãã©ã ããèŠæ±ããããšããããŸããã ãŸããIHttpRequestã€ã³ã¿ãŒãã§ã€ã¹ã®å®è£ ã«ã€ããŠã¯èšåããŸããã§ãããããã¯ãlibeventãããã¡ãŒã䜿çšããã«ãŒãã³äœæ¥ã«ã¯ã»ãšãã©é¢å¿ããªãããã§ãã æ®ãã«ã€ããŠã¯ãæçµããŒãžã§ã³ã®ã³ãŒããèŠããšãããŸãå€æŽãããŠããŸããã å°ãã®ä¿®æ£ãšå°ãã®ããã¥ãŒãã³ã°ããè¿œå ãããŸããã
ãŠãŒã¶ãŒãµãŒããŒã¯ããã¹ãŠã®çš®é¡ã®httpèŠæ±ãåŠçããå¿ èŠã¯ãããŸããã , libevent evhttp_set_allowed_methods ( GET). libevent , .
: . «» - http- evhttp_set_max_headers_size evhttp_set_max_body_size. , . . - , , âŠ
, GET ( ) , .
http-
#include "http_server.h" #include "http_headers.h" #include "http_content_type.h" #include <iostream> #include <sstream> #include <mutex> int main() { char const SrvAddress[] = "127.0.0.1"; std::uint16_t SrvPort = 5555; std::uint16_t SrvThreadCount = 4; std::string const RootDir = "../test_content"; std::string const DefaultPage = "index.html"; std::mutex Mtx; try { using namespace Network; HttpServer Srv(SrvAddress, SrvPort, SrvThreadCount, [&] (IHttpRequestPtr req) { std::string Path = req->GetPath(); Path = RootDir + Path + (Path == "/" ? DefaultPage : std::string()); { std::stringstream Io; Io << "Path: " << Path << std::endl << Http::Request::Header::Host::Name << ": " << req->GetHeaderAttr(Http::Request::Header::Host::Value) << std::endl << Http::Request::Header::Referer::Name << ": " << req->GetHeaderAttr(Http::Request::Header::Referer::Value) << std::endl; std::lock_guard<std::mutex> Lock(Mtx); std::cout << Io.str() << std::endl; } req->SetResponseAttr(Http::Response::Header::Server::Value, "MyTestServer"); req->SetResponseAttr(Http::Response::Header::ContentType::Value, Http::Content::TypeFromFileName(Path)); req->SetResponseFile(Path); }); std::cin.get(); } catch (std::exception const &e) { std::cout << e.what() << std::endl; } return 0; }
ãããã«
libevent . : . , http-. github . http server .
:
ab -c 1000 -k -r -t 10 http://localhost:8888/libevent_test_http_srv.zip
Server Software: test
Server Hostname: test
Server Port: 8888
Document Path: /libevent_test_http_srv.zip
Document Length: 23756 bytes
Concurrency Level: 1000
Time taken for tests: 10.012 seconds
Complete requests: 2293
倱æãããªã¯ãšã¹ãïŒ0
æžã蟌ã¿ãšã©ãŒïŒ0
Keep-Alive requests: 2293
Total transferred: 60628847 bytes
HTML transferred: 60328370 bytes
Requests per second: 229.02 [#/sec] (mean)
Time per request: 4366.365 [ms] (mean)
Time per request: 4.366 [ms] (mean, across all concurrent requests)
Transfer rate: 5913.65 [Kbytes/sec] received
Server Hostname: test
Server Port: 8888
Document Path: /libevent_test_http_srv.zip
Document Length: 23756 bytes
Concurrency Level: 1000
Time taken for tests: 10.012 seconds
Complete requests: 2293
倱æãããªã¯ãšã¹ãïŒ0
æžã蟌ã¿ãšã©ãŒïŒ0
Keep-Alive requests: 2293
Total transferred: 60628847 bytes
HTML transferred: 60328370 bytes
Requests per second: 229.02 [#/sec] (mean)
Time per request: 4366.365 [ms] (mean)
Time per request: 4.366 [ms] (mean, across all concurrent requests)
Transfer rate: 5913.65 [Kbytes/sec] received
âŠ
!