- 1 Project epHttpd
- 1.1 HTTP ÇÁ·ÎÅäÄÝ : ?IExplorerÀÇ query¿Í ¼¹ö response ºÐ¼®
- 1.2 ¼¹öÀÇ ±¸Çö °³¿ä
- 1.3 ?TTextClient : Text/Line Protocol ±¸Çö
- 1.3.1 Text/Line ÇÁ·ÎÅäÄÝÀÇ ±âº»Å¬·¡½º ?TTextClient ±¸Çö
- 1.3.2 TTextClient:?:OnRead() ±¸Çö
- 1.4 ?THttpClient Ŭ·¡½º ±¸Çö
- 1.4.1 THttpClient:?:OnIdle()ÀÇ ±¸Çö : ¸Þ¼¼Áö ºÐ¼® & ó¸®
- 1.4.2 HTTP º»Ã¼ Àü¼Û
- 1.5 EpollSocket ÀÇ ¼öÁ¤
- 1.6 Signal Çڵ鷯
- 1.7 ¼Ò½º
¿©Å±îÁöÀÇ ÀÛ¾÷À» ±â¹ÝÀ¸·Î, ÀÌÁ¦´Â Epoll ±â¹ÝÀÇ httpd ¼¹ö, Áï À¥¼¹ö¸¦ ±¸ÇöÇغ¸·Á°í ÇÑ´Ù. ±×·¸´Ù°í Çؼ httpd 1.0/1.1 ÀÇ ÇÁ·ÎÅäÄÝÀ» ´Ù ±¸ÇöÇÏ´Â°Ô ¾Æ´Ï¶ó,
GET /
GET /index.html
GET /sample.jpg
°£´ÜÇÑ GET ÇÁ·ÎÅäÄÝÀ» ó¸®ÇÏ´Â - ÆÄÀÏÀü¼Û¼¹ö ¼öÁØÀÇ - °£´ÜÇÑ ¼¹ö´Ù. ÀÌ ÇÁ·ÎÁ§Æ®´Â °øºÎ¸ñÀû ȤÀº »ó¿ëÀ¥¼¹ö Á¦ÀÛ¸ñÀûÀ̶ó±âº¸´Ù´Â ´ÙÀ½À» ±¸ÇöÇϴµ¥ ÀÇÀÇ°¡ ÀÖ´Ù.
- Text ±â¹Ý ÇÁ·ÎÅäÄÝ ( ÇÑ ¶óÀÎÀÇ ³¡ÀÌ CR ȤÀº CR,LF·Î ³¡³ª´Â ÀϹÝÀûÀÎ ¶óÀαâ¹Ý )ÀÇ ±¸Çö
- Send Buffering À» ÅëÇÑ ´ë¿ë·® Àü¼Û
- epoll ½ºÆ®·¹½º Å×½ºÆ®
epoll°ü·ÃµÈ À¥ °ÁÂ, »ùÇÃÇÁ·Î±×·¥µéÀ» ±¸ÇÒ ¼ö´Â ÀÖÀ¸³ª ¼¼¹ÐÇÑ ¿¡·¯Ã³¸®°¡ Æ÷ÇÔµÈ ¾ÈÁ¤µÈ ¼¹ö¼Ò½º´Â ã±â Èûµé´Ù. ÀÌ ÇÁ·ÎÁ§Æ®´Â, ±âÁ¸ »ùÇÃÇÁ·Î±×·¥µéÀ» »ó¿ë¼¹ö, Áï »ó¾÷Àû ÀÌ¿ëÀÌ °¡´ÉÇÑ ¼öÁØÀÇ ÇÁ·Î±×·¥µéÀ» ±¸ÇöÇÏ°íÀÚ ÇÑ´Ù. (°ú¿¬ ... -_-;;;)
1.1 HTTP ÇÁ·ÎÅäÄÝ : ?IExplorerÀÇ query¿Í ¼¹ö response ºÐ¼® #
GET / HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/msword, application/vnd.ms-excel,
application/vnd.ms-powerpoint, application/x-shockwave-flash, */*
Accept-Language: ko
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461)
Host: 192.168.0.90:8000
Connection: Keep-Alive
[¿©±â¿¡ CRLF¸¸À» Æ÷ÇÔÇÏ´Â ÇϳªÀÇ ºó ¶óÀÎÀÌ ¹Ýµå½Ã Á¸Àç]
±×³É ´Ü¼øÇÏ°Ô ´ýÇÁÇÏ´Â ¼¹ö¸¦ µ¹·Á³õ°í, Internet Explorer¸¦ Á¢¼Ó½ÃÄѺôÙ. ±×·¨´õ´Ï À§¿Í°°Àº °á°ú°¡ ³ª¿Ô´Ù (192.168.0.90:8000Àº ÇÊÀÚ°¡ ¾²°íÀÖ´Â ¼¹öÀÇ ÁÖ¼Ò:Æ÷Æ®¹øÈ£ ÀÌ´Ù). ¿©±â¼ ¿ì¸®°¡ Áý¾î³»¾ß ÇÒ Ç׸ñÀº
GET / ÀÌ°í ´Ù¸¥°Í¿¡´Â °ü½ÉÀÌ ¾ø´Ù. ÀÌ °á°ú´Â IE¿¡¼
http://192.168.0.90:8000/ ÇÑ°ÍÀÌ°í ¸¸¾à
http://192.168.0.90:8000/image.jpg ·Î ÀÔ·ÂÀ» Çϸé,
GET /image.jpg HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/msword, application/vnd.ms-excel,
application/vnd.ms-powerpoint, application/x-shockwave-flash, */*
Accept-Language: ko
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461)
Host: 192.168.0.90:8000
Connection: Keep-Alive
[¿©±â¿¡ CRLF¸¸À» Æ÷ÇÔÇÏ´Â ÇϳªÀÇ ºó ¶óÀÎÀÌ ¹Ýµå½Ã Á¸Àç]
ÀÌ¿¡ ´ëÇÑ ÀÀ´äÀº ´ÙÀ½°ú °°Àº ÇüŸ¦ ¶í´Ù.
HTTP/1.0 200 OK
Date: Thu, 03 May 1997 16:04:09 GMT
Server: NCSA/1.4.2
MIME-version: 1.0
Content-type: text/html
Last-moidified: Thu, 03 May 1997 16:03:27 GMT
Content-length: 145
[¿©±â¿¡ CRLF¸¸À» Æ÷ÇÔÇÏ´Â ÇϳªÀÇ ºó ¶óÀÎÀÌ ¹Ýµå½Ã Á¸Àç]
[½ÇÁ¦ µ¥ÀÌÅÍ]
Áï, ¿ì¸®°¡ ¸¸µé ¼¹ö´Â ÀÌ·±Çü½ÄÀÇ ÀÀ´äÀ» ÇØ ÁÖ¾î¾ß ÇÑ´Ù. ùÁÙÀÇ 200 À̶ó´Â ¼ýÀÚ´Â HTTP ÀÀ´äÄÚµå·Î ¼º°øÀÇ ÀǹÌÀÌ°í, ¸¸¾à¿¡ ÆÄÀÏÀ» ãÁö ¸øÇϸé 404, ¾ï¼¼½º±ÇÇÑÀÌ ¾øÀ¸¸é 403À» ¸®ÅÏÇÑ´Ù. Content-typeÀº ¿ì¸®°¡ ½÷ ÁÖ¾î¾ß ÇÒ ÀÚ·áÀÇ Çü½ÄÀε¥ text/hmtl, image/jpeg, ... ÀÇ Çü½Ä.
À§¿Í °°Àº http Çì´õ µÚ¿¡ ºóÁÙ Çϳª°¡ µé¾î°¡°í ½ÇÁ¦ ÆÄÀÏÀÇ ³»¿ëÀÌ ´ã±â°Ô µÈ´Ù.
1.2 ¼¹öÀÇ ±¸Çö °³¿ä #
ephttpd´Â ´ÙÀ½°ú °°Àº ó¸® È帧À» °¡Áö°í ±¸ÇöÇÒ °ÍÀÌ´Ù.
- Ŭ¶óÀ̾ðÆ®°¡ ¿¬°áµÇ¸é 'GET ...' ÀÇ request¸¦ º¸³¾ °ÍÀÌ´Ù.
- ´Ù¸¥ ³»¿ëÀº ´Ù ¹«½ÃÇÏ°í GET µÚÀÇ urlÀ» ÃßÃâÇÑ´Ù.
- url·ÎºÎÅÍ ½ÇÁ¦ ÆÄÀÏÀ» ã¾Æº¸°í ÇØ´çÆÄÀÏÀ» ¿¾î Àü¼ÛÇÑ´Ù.
ÀÌ °úÁ¤¿¡¼, ¿©·¯°¡ÁöÀÇ º¸Á¶ ·çƾµéÀ» ÇÊ¿ä·Î ÇÏ¸ç ¸ðµÎ Á¦ÀÛÇÒ °ÍÀÌ´Ù.
- ÅؽºÆ® ÇÑÁÙÀ» °ø¹é±âÁØÀ¸·Î À߶󳻴 Token ÇÔ¼ö
- »ó´ë url·ÎºÎÅÍ ÆÄÀÏÀÇ Àý´ëÀ§Ä¡¸¦ ¾ò¾î³»´Â ÇÔ¼ö, ´Ü ÇØÅ·ÀÇ À§ÇèÀÌ Àֱ⿡ url¿¡¼ ..µîÀ» °ÅºÎÇÏ´Â ±â´É ±¸Çö
- HTTP Çì´õ »ý¼º ÇÔ¼ö (»çÀÌÁî, ¼öÁ¤ÀÏÀÚ µî)
´Ù¸¸, ÀÌ ¼¹ö°¡ ½ÇÁ¦ À¥¼¹ö¸¦ ´ëüÇϱâÀ§ÇØ °³¹ßµÇ´Â °ÍÀÌ ¾Æ´Ï¹Ç·Î ´ÙÀ½ÀÇ °ÍµéÀº ±¸ÇöÇÏÁö ¾ÊÀ» °ÍÀÌ´Ù.
- URLENCODE, URLDECODE : url Ç¥Áر԰ݿ¡ ¸ÂÃß±â À§ÇØ °ø¹éÀÌ %20·Î ´ëüµÈ °æ¿ìµî¿¡ ´ëÇÑ µðÄÚµù
- ÇѱÛÆÄÀÏÀ̸§Ã³¸® : url¿¡ Çѱ۵î Ư¼ö¹®ÀÚ°¡ Æ÷ÇԵǾúÀ» °æ¿ì¿¡ ´ëÇÑ Ã³¸®
- µð·ºÅ丮 ºê¶ó¿ì¡ : ÆÄÀÏÀ» ¿äûÇÑ°ÍÀÌ ¾Æ´Ï°í µð·ºÅ丮¸¦ ¿äûÇßÀ» °æ¿ì¿¡ ´ëÇÑ Ã³¸®
- CGI ÀÎÅÍÆäÀ̽º ±¸Çö
- php¿£Áøµî°úÀÇ ¿¬°á
- ·Î±ë
- ±âŸµîµî
1.3 ?TTextClient : Text/Line Protocol ±¸Çö #
ÀÏ´Ü °¡º±°Ô ¶°¿À¸£´Â ±¸Çö ¼ø¼´Â ÀÌ·¸´Ù.
- ?OnIdle¿¡¼, recvbuf.View(...)¸¦ ÅëÇØ ¶óÀκ극ÀÌÄ¿(CRLF)°¡ µé¾î¿Ô´ÂÁö È®ÀÎ
- µé¾î¿Ô´Ù¸é, ÇÑ ¶óÀÎ ²¨³»±â (View&Skip ȤÀº Pop)
ÇÏÁö¸¸, View ÇÔ¼ö ³»ºÎÀûÀ¸·Î º¹»ç¸¦ ¼öÇàÇϹǷΠ´ÜÁö ÇÑ ¶óÀÎÀÌ µé¾î¿Ô´ÂÁö¸¦ °Ë»çÇÏ´Â ¸ñÀûÀ¸·Î´Â ³¶ºñ°¡ ½ÉÇÏ´Ù. ±×·¡¼,
?TBinQueueÀÇ ¼öÁ¤À» ÇÊ¿ä·Î ÇÑ´Ù.
»õ·Î¸¸µé Ŭ·¡½º´Â
?TTextQueue. ÀÚ¼¼ÇÑ ±¸ÇöÀº º°µµ ¹®¼·Î Á¤¸®ÇÏ¿´´Ù(
TextBuffering). ÀÌ Å¬·¡½º¸¦ ÀÌ¿ëÇÏ¿© ´ÙÀ½°ú °°Àº ¼ø¼·Î ±¸ÇöÇÑ´Ù.
- ?OnRead¿¡¼, µé¾î¿Â µ¥ÀÌÅ͸¦ ¹Ù·Î ?TextQueue¿¡ ³Ö´Â´Ù.
- ?OnIdle¿¡¼, recvlist.empty()·Î µé¾î¿Â µ¥ÀÌÅÍ°¡ ÀÖ´ÂÁö È®ÀÎÇÏ°í ²¨³»¼ ó¸®
1.3.1 Text/Line ÇÁ·ÎÅäÄÝÀÇ ±âº»Å¬·¡½º ?TTextClient ±¸Çö #
#define MAX_LINE 256
#define MAX_BUF 819200
class TTextClient : public TEpollClient
{
protected :
TTextQueue *recvlist;
TBinQueue *sendbuf;
int nin, nout;
bool is_would_block;
bool is_error;
virtual int internalbuffersize(void) { return MAX_BUF; };
virtual int Flush(void);
public :
TTextClient(const int lfd, const char *laddr) : TEpollClient(lfd, laddr)
{
recvlist = new TTextQueue(MAX_LINE);
sendbuf = new TBinQueue(internalbuffersize());
nin = nout = 0;
is_would_block = is_error = false;
};
~TTextClient()
{
delete recvlist;
delete sendbuf;
};
virtual int OnWrite(void);
virtual int OnRead(void);
virtual int OnIdle(void);
virtual int OnError(const int);
};
?TBasicClient¸¦ »ó¼Ó¹Þ¾Æ¼ ±¸ÇöÇÏ·Á´Ù°¡, ¸î°¡Áö ¹ø°Å·Î¿î ¹®Á¦µéÀÌ ÀÖ¾î¼ Binary¿ë°ú Text¿ëÀÇ
?BasicClient Ŭ·¡½º¸¦ °¢°¢ ¸¸µé±â·Î Çß´Ù. µÎ Ŭ·¡½ºÀÇ µ¿ÀÛ¹æ½ÄÀº ´Ù ¶È°°Áö¸¸,
?OnRead ¿¡¼ ¹ÙÀ̳ʸ® ¹öÆÛ¸µÀ» ÇÏ´À³Ä ÅؽºÆ® ¹öÆÛ¸µÀ» ÇÏ´À³ÄÀÇ Â÷ÀÌÀÌ´Ù. ³ªÁß¿¡ ½Ã°£ÀÌ ´õ µÇ¸é (°ú¿¬ --;;) µÎ Ŭ·¡½ºÀÇ °øÅëºÐ¸ð¸¦ »Ì¾Æ³»¼
?TEpollClient -
?TBasicClient -
?TBinClient ¿Í
?TEpollClient -
?TBasicClient -
?TTextClientÀÇ Ã¼°è¸¦ °¡Áöµµ·Ï ±¸¼ºÇØ º¸°í´Â ½Í´Ù.
?TTextClient´Â sendbuffer¿¡ ´ëÇؼ´Â ¹ÙÀ̳ʸ®¿Í ÅؽºÆ® ±¸ºÐ¾øÀÌ ¶È°°ÀÌ ¹ÙÀ̳ʸ®·Î ó¸®Çϵµ·Ï Çß´Ù. ´Ù¸¸ ³ªÁß¿¡ »ç¿ëÀÚ ÆíÀǸ¦ À§ÇØ
?SendText³ª
?SendLine °°Àº ¸Þ½îµå¸¦ Á¦°øÇØ ÁÙ °ÍÀÌ´Ù. recvbuffer´Â ¹ÙÀ̳ʸ®ÀÇ °æ¿ì¿Í ±¸ºÐÇϱâ À§ÇØ recvlist¶ó°í À̸§ºÙ¿´´Âµ¥ char *ÀÇ list±¸Á¶·Î ¼±¾ðÇÏ¿´´Ù.
1.3.2 TTextClient:?:OnRead() ±¸Çö #
int TTextClient::OnRead(void)
{
char buf[SIZE_OSBUF];
int nread = read(fd, buf, SIZE_OSBUF);
if(nread == 0) return EP_ERROR_READ_CLOSE;
else if(nread < 0){
if(errno == EAGAIN) return EP_ERROR_NONE;
return EP_ERROR_READ_GEN;
}
if(recvlist->Push(nread, buf) < 0){
// cout << "read overflow\n";
return EP_ERROR_READ_OVERFLOW;
}
nin += nread;
return EP_ERROR_NONE;
};
¹ÙÀ̳ʸ® Ŭ·¡½º¿Í Å©°Ô ´Ù¸£Áö ¾Ê´Ù. recvbuf´ë½Å¿¡ recvlist(Áï,
?TTextQueue)¿¡ µ¥ÀÌÅ͸¦ ³ÖÀ» »ÓÀÌ´Ù. ¸¶Âù°¡Áö·Î ÀÌ °÷¿¡¼ ¹Ù·Î µé¾î¿À´Â µ¥ÀÌÅ͸¦ ºÐ¼®&ó¸®ÇÏÁö ¾Ê°í ¼ÒÄÏ¿¡¼ µ¥ÀÌÅ͸¦ ÀÐ¾î ½×´Â ÀÛ¾÷¸¸À» Çϵµ·Ï Çß´Ù. ½ÇÁ¦ ó¸®&ºÐ¼®Àº
?OnIdle ¿¡¼ ¼öÇàÇÒ °ÍÀÌ´Ù.
recvlist->PushÀÇ ¸®ÅÏ°ªÀÌ 0 ÀÎ °æ¿ì´Â, µ¥ÀÌÅÍ´Â µé¾î¿ÔÁö¸¸ ÇÑ ¶óÀÎÀ» ä¿ìÁö ¸øÇÑ °æ¿ì·Î ºÁ¾ßÇϹǷΠ¿¡·¯Ã³¸® ÇÏÁö ¾Ê°í, 0 º¸´Ù ÀÛÀº °æ¿ì¿¡ ¿¡·¯ ó¸®Çϵµ·Ï ÇÏ¿´´Ù. ¿¡·¯´Â µÎ Á¾·ùÀÏÅÙµ¥ BUF_ERROR_MAX_LINE (ÇÑ ¶óÀÎÀÌ ³Ê¹« ±æ´Ù)¿Í BUF_ERROR_MAX_LIST (º¸°üµÈ ¶óÀÎ ¼ýÀÚ°¡ ³Ê¹« ¸¹´Ù). Ưº°È÷ ó¸®ÇÏÁö ¾Ê°í ¿¡·¯¸®ÅÏ ÇÏ°Ô ÇÏ¿´´Âµ¥ ÀÌ °á°ú·Î ÀÌ ¼ÒÄÏÀÇ ¿¬°áÀº ²÷¾îÁú °ÍÀÌ´Ù.
ÀÌ µÎ Á¾·ùÀÇ ¿¡·¯ 󸮴 ³°¨ÇÏ´Ù. ù°´Â ÇÁ·ÎÅäÄÝ ±Ô¾àÀ» ÁؼöÇÏÁö ¾Ê¾ÒÀ» È®·üÀÌ ³ô°í µÎ¹ø°´Â ¼¹ö°¡ ó¸®ÇÏ´Â °Íº¸´Ù ÈξÀ ¸¹Àº µ¥ÀÌÅÍ°¡ ¼ö½ÅµÈ °æ¿ìÀÏ È®·üÀÌ ³ô´Ù. ÀÌ µÎ°¡Áö »óȲÀÌ ÀϾÁö ¾Êµµ·Ï ÇÏ´Â°Ô ÁÁ°ÚÁö¸¸, ¿©À¯°¡ µÈ´Ù¸é »ó¼öµéÀ» ³Ë³ËÇÑ ¼ýÀÚ·Î Àâ¾ÆÁÖ¸é ¿À·ù¸¦ ÃÖ´ëÇÑ ÁÙÀÏ ¼ö ÀÖÀ» °ÍÀÌ´Ù. (MAX_LINE, MAX_LIST in buffer.h)
1.4 ?THttpClient Ŭ·¡½º ±¸Çö #
?TTextClient ¸¦ ±â¹ÝÀ¸·Î,
?THttpClient¸¦ ±¸ÇöÇÑ´Ù. ´ëºÎºÐÀÇ ÀÔÃâ·Â󸮴Â
?TTextClient°¡ ÇØÁÙ°ÍÀÌ°í,
?THttpClient´Â
?OnIdle ¸¸ ±¸ÇöÇÑ´Ù.
1.4.1 THttpClient:?:OnIdle()ÀÇ ±¸Çö : ¸Þ¼¼Áö ºÐ¼® & ó¸® #
¿©±â±îÁö Çؼ Ŭ¶óÀ̾ðÆ®¿¡¼ º¸³½ µ¥ÀÌÅ͸¦ ¶óÀκ°·Î ¼Õ¿¡ ³Ö¾ú´Ù! °¢ ¶óÀÎÀ» ¾î¶»°Ô ó¸®ÇÒ °ÍÀΰ¡´Â ¿ª½Ã »ç¿ëÀÚÀÇ ¸òÀÌ´Ù. °è¼ÓÇؼ ¿Ï¼ºµµ ³ôÀº À¥¼¹ö·Î ¸¸µé¾î °¡°íÀÚ ÇÑ´Ù¸é, ºóÁÙÀÌ µé¾î¿Ã¶§±îÁö¸¦ ÇϳªÀÇ Çì´õ±¸Á¶·Î ¹¾î °ü¸®ÇÒ ÇÊ¿ä°¡ ÀÖ´Ù. ÀÌ ±Û¿¡¼´Â °£´ÜÇÏ°Ô 'GET' À¸·Î ½ÃÀ۵Ǵ ¶óÀο¡¸¸ °ü½ÉÀ» °¡Áö°í ºÐ¼® ó¸®ÇÒ °ÍÀÌ´Ù.
- ÇÑ ¶óÀξ¿ ²¨³»¼ óÀ½ 3 ¹ÙÀÌÆ®°¡ 'GET' À¸·Î ½ÃÀÛÇÏ´ÂÁö °Ë»çÇÏ°í,
- °ø¹éÀ» ±âÁØÀ¸·Î ÅäÅ«À» ºÐ¸®ÇÏ¿©,
- µÎ¹ø° ÅäÅ«À» ±âÁØÀ¸·Î Àý´ë ÆÄÀÏ°æ·Î¸¦ ¿Ï¼º
- Àü¼Û·çƾÀ¸·Î Àü´Þ
ÇÑ ¶óÀξ¿ ²¨³»¼ ó¸®Çϱâ
....
while(! recvlist->empty()){
char buf[MAX_LINE];
if(recvlist->Pop(buf) < 1) break;
....
}
....
ȤÀº,
....
char buf[MAX_LINE];
while( recvlist->Pop(buf) > 0 ){
....
}
....
ÀÌ·±½ÄÀ¸·Î ÇѶóÀξ¿ ²¨³» ó¸®ÇÑ´Ù. TTextQueue:
?:PopÀº ²¨³¾ ¶óÀÎÀÌ ¾øÀ»°æ¿ì 0À», Á¤»óÀΰæ¿ì 1À» ¸®ÅÏÇÑ´Ù.
ÅäÅ«ºÐ¸®
ÅäÅ«ºÐ¸®´Â
¾ÆÁÖ¾ÆÁÖ ¸¹ÀÌ ¾²ÀÌ´Â ±â¼úÀÌ´Ù. ±×·¡¼ ³¯Àâ¾Æ µû·Î Á¤¸®¸¦ ÇÒ °ÍÀÌÁö¸¸, ¿©±â¼´Â strchrÀ» ÀÌ¿ëÇؼ °£´ÜÈ÷ ±¸ÇöÇß´Ù. ÀÌ ÇÔ¼ö´Â °ø¹éÀ» ±âÁØÀ¸·Î À߶󳽴ÙÀ½ vector ÄÁÅ×À̳ʿ¡ ´ã¾Æ ÁØ´Ù. strtok ÇÔ¼ö°¡ ÀÌ·²¶§ ¾²¶ó°í ÀÖ±â´Â ÇÏÁö¸¸ ¿©·¯°¡Áö ¹ø°Å·Î¿î ¹®Á¦°¡ ÀÖ¾î¼ »ç¿ëÇÏÁö ¾Ê¾Ò´Ù.
int tokens(const char *s, vector<const char *> &vToken)
{
vToken.clear();
char *sptr, *nptr;
int nt;
int n, nsize = strlen(s);
while(*s){
sptr = strchr(s, ' ');
if(!sptr) break;
nt = sptr - s;
nptr = new char[nt+1];
strncpy(nptr, s, nt);
nptr[nt] = 0;
vToken.push_back(nptr);
s = ++sptr;
}
if(*s) vToken.push_back(s);
return vToken.size();
}
template <class ForwardIterator>
void sequence_delete(ForwardIterator first, ForwardIterator last)
{
while (first != last)
delete *first++;
}
¸Þ¼¼ÁöºÐ¼®À» ÅëÇØ ¿äû url ¾ò¾î³»±â
while(recvlist->Pop(buf) > 0){
if( strncmp(buf, "GET", 3) ) continue;
do {
std::vector<const char *> ve;
ntoken = tokens(buf, ve);
if(ntoken < 2) continue;
msgGET(ve[1]);
} while(0);
}
ÇÑÁÙ¾¿ ²¨³»¼, óÀ½ ¼¼±ÛÀÚ°¡ 'GET'À¸·Î ½ÃÀ۵ǴÂÁö ÆľÇÇÑÈÄ °ø¹é±âÁØÀ¸·Î À߶󳽴Ù. ÀÌ °ªÀ» msgGET : GET ¸Þ¼¼Áöó¸®ÇÔ¼ö·Î Àü´ÞÇÑ´Ù. do... while(0) Àº Àǹ̾øÀÌ »ç¿ë -
?OnIdle ÀÌ ¼öµµ¾øÀÌ È£ÃâµÇ¹Ç·Î º¯¼ö»ý¼ºÀ» È¿À²ÀûÀ¸·Î Çϱâ À§ÇØ »ç¿ëÇÏ¿´´Ù.
=== HTTP Çì´õ Àü¼Û===
msgGET()
#define DEFAULT_DOC "index.html"
int THttpClient::msgGET(const char *url)
{
int httpcode = 200;
char filename[MAX_LINE], mime[MAX_LINE];
getcwd(filename, MAX_LINE);
strcat(filename, url); // make the full filename
// url ÀÇ ¸¶Áö¸·ÀÌ / ¶ó¸é,
if( filename[strlen(filename) - 1] == '/' ) strcat (filename, DEFAULT_DOC);
// url ¿À·ù°Ë»ç
if( (filename[0] != '/') || (strstr(filename, "..") != NULL) ) httpcode = 500;
....
¿äû url·ÎºÎÅÍ Ç®Æо²ÆÄÀϳ×ÀÓÀ» ¸¸µé¾î³½´Ù. ¿äûurlÀÇ ³¡ÀÌ '/' ÀÏ °æ¿ì (¿¹¸¦ µé¾î
http://www.yahoo.com/)´Â µðÆúÆ® µµÅ¥¸ÕÆ® À̸§À¸·Î ÇÑ´Ù. À¥ºê¶ó¿ìÀú´Â Ç×»ó urlÀÌ '/'·Î ½ÃÀÛÇϵµ·Ï Á¶Á¤À» Çϴµ¥, ÀÌ ¹®ÀÚ·Î ½ÃÀÛÇÏÁö ¾Ê°Å³ª url ¿¡ '..'ÀÌ Æ÷ÇԵǴ °æ¿ì´Â ¿¡·¯·Î ó¸®Çϵµ·Ï ÇÏ¿´´Ù - ¿¡·¯¶ó°í ÇÏ´õ¶óµµ 500 ÄÚµå·Î ÀÀ´äÇØ ÁÖµµ·Ï ÇÑ´Ù.
ÆÄÀÏ»óÅ °Ë»ç
// stat ¾ò¾î³¿
struct stat fileinfo;
if ( stat(filename, &fileinfo) == -1)
{
switch(errno){
case ENOENT : // file not found
httpcode = 404;
break;
case EACCES : // permission denied
httpcode = 403;
break;
default : // some error
httpcode = 500;
}
ResponseHeader(httpcode);
} else {
get_http_mime_type(filename, mime);
ResponseHeader(httpcode, fileinfo.st_mtime, fileinfo.st_size, mime);
}
unstd.hÀÇ stat ÇÔ¼ö¸¦ ÀÌ¿ëÇؼ, ÆÄÀÏ »óŸ¦ °£´ÜÈ÷ Á¶»çÇÑ´Ù. ÆÄÀÏÀÇ Á¸Àç À¯¹«¿Í ¾ï¼¼½º ±ÇÇÑ°Ë»ç, ÆÄÀÏŸÀÔ(¸µÅ©ÀÎÁö..µîµî)À» °Ë»çÇÒ ¼ö ÀÖ°í, ¼º°øÇϸé struct stat¿¡ ÆÄÀÏÀÇ »ó¼¼Á¤º¸ (»ý¼º³¯Â¥, ¼ÒÀ¯ÁÖ, ±ÇÇÑ µîµî)¸¦ ¾Ë·ÁÁִµ¥ ÀÌ °ªµéÀ» ÀÀ´äÇÔ¼ö¿¡ Àü´ÞÇϵµ·Ï Çß´Ù. get_http_mime_type À̶ó´Â ÇÔ¼ö¸¦ Àӽ÷ΠÇϳª ¸¸µé¾ú´Âµ¥, ½Ã½ºÅÛ¿¡¼ º°µµ·Î °ü¸®¸¦ ÇϹǷΠ½Ã°£À̵ȴٸé(^^;) ½Ã½ºÅÛ¿¡ µî·ÏµÈ ¸¶ÀÓÀ» ¾ò¾î³»µµ·Ï °íÃÄ º¸ÀÚ.
mime ¾ò¾î³»±â
#define MIME_DEFAULT "text/plain"
int get_http_mime_type(const char *file, char *outbuffer)
{
char *ptr = strrchr(file, '.');
if(! ptr) strcpy(outbuffer, MIME_DEFAULT);
else if(!strcmp(ptr, "jpg")) strcpy(outbuffer, "image/jpeg");
else if(!strcmp(ptr, "html")) strcpy(outbuffer, "text/html");
else strcpy(outbuffer, MIME_DEFAULT);
return 1;
}
´Ü¼øÈ÷ È®ÀåÀÚ¸¦ °Ë»çÇؼ ¸î°¡Áö Á¾·ùÁß¿¡¼ ÇØ´çµÇ´Â ¸¶ÀÓÀ» ¸®ÅÏÇϵµ·Ï Çß´Ù.
?ResponseHeader : ÀÀ´ä Çì´õ Àü¼Û
int THttpClient::ResponseHeader(const int errcode, const time_t mtime, const int csize, const char *mime)
{
char buf[MAX_LINE], errstr[MAX_LINE], datestr[MAX_LINE], mimestr[MAX_LINE];
switch(errcode){
case 200 : strcpy(errstr, "OK");
break;
case 404 : strcpy(errstr, "Object Not Found");
break;
case 403 : strcpy(errstr, "Permission Denied");
break;
case 500 : strcpy(errstr, "Internal Server Error");
break;
}
time_t tt;
time(&tt);
get_http_gmtime_str(tt, datestr);
sprintf(buf, "HTTP/1.0 %d %s\n"
"Date: %s GMT\n"
"Server: %s\n", errcode, errstr, datestr, SERVER);
sendbuf->Push(strlen(buf), buf);
if(errcode == 200){
get_http_gmtime_str(mtime, datestr);
sprintf(buf, "Last-modified: %s\n"
"Content-type: %s\n"
"Content-Length: %d\n" , datestr, mime, csize);
sendbuf->Push(strlen(buf), buf);
} else {
sprintf(buf, "Content-Length: %d\n" , 0);
}
sendbuf->Push(2, CRLF);
return 0;
}
º¸´Â°Íó·³, Çì´õ³»¿ëÀ» ¸¸µé¾î³»´Â ÇÔ¼öÀÌ´Ù. Çì´õÀÇ ³¡Àº ºóÁÙÀ̹ǷÎ, ¸¶Áö¸·¿¡ ºóÁÙ Çϳª º¸³»ÁÖ´Â°Í ÀØÁö ¸»ÀÚ. Çì´õ³»¿ëÁß¿¡ ³¯Â¥°ü·ÃµÈ °÷ÀÌ 2°³°¡ Àִµ¥(Date: ¿Í Last-modified: ), HTTP ÀÀ´ä¿¡¼, ÀÀ´ä½Ã°£ ¹× ÄÁÅÙÃ÷ÀÇ ÃÖÁ¾¼öÁ¤½Ã°£ Çü½ÄÀº GMT¸¦ ±âÁØÀ¸·Î ÇϹǷΠget_http_gmtime_strÇÔ¼ö¸¦ Á¦ÀÛÇÏ¿´´Ù.
int get_http_gmtime_str(const time_t tt, char *outbuffer)
{
// Çü½Ä : Thu, 03 May 1997 16:04:09
char *dow[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
char *mon[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
struct tm *ttm = gmtime(&tt);
sprintf(outbuffer, "%s, %02d %s %04d %02d:%02d:%02d",
dow[ttm->tm_wday], ttm->tm_mday, mon[ttm->tm_mon],
ttm->tm_year + 1900, ttm->tm_hour, ttm->tm_min, ttm->tm_sec
);
return 1;
}
struct tm ÀÇ Çü½ÄÀº, °¡²û È¥¶õ½º·¯¿îµ¥ ¿äÀÏ, ¿ùÀº 0ºÎÅÍ ½ÃÀÛÇÏ°í, ¿¬µµ´Â 1900³âºÎÅÍ ½ÃÀÛÇÑ´Ù. ³ª¸ÓÁö°ªµéÀº ¿¹»óÇϴ´ë·Î »ó½ÄÀûÀÌÁö¸¸, ¿äÀÏ&¿ù&³âÀº ÁÖÀÇÇØ¾ß ÇÑ´Ù. ÀÌ ±¸Á¶Ã¼¿¡¼ y2k ¹®Á¦´Â ¹ß»ýÇÏÁö ¾Ê´Â´Ù. GMT¸¦ ¾ò¾î³»±â À§ÇØ gmtimeÀ» È£ÃâÇߴµ¥, ÇöÀç ½Ã½ºÅÛÀÇ ·ÎÄÉÀÏ¿¡ ¸Â´Â ½Ã°£ (Áï, ÇöÀç½Ã°£)Àº localtimeÀ¸·Î ¾ò¾î³½´Ù.
ÀÌ·¸°Ô Çؼ Çì´õ Àü¼ÛÀº ¸¶¹«¸®ÇÏ°í, ÀÌÁ¦ ÄÁÅÙÃ÷ º»Ã¼¸¦ Àü¼ÛÇØ¾ß ÇÑ´Ù.
1.4.2 HTTP º»Ã¼ Àü¼Û #
º»Ã¼ Àü¼ÛÀº ÆÄÀÏÀ» ÀÐ¾î¼ ±× ³»¿ëÀ» Àü¼ÛÇØÁÖ¸é µÈ´Ù. ½±´Ù? ÇÏÁö¸¸ °ñÄ¡¾ÆÇ ¹®Á¦°¡ Çϳª ¼û¾îÀÖ´Ù. ÆÄÀÏ »çÀÌÁî°¡ ¼¾µå¹öÆÛ »çÀÌÁ´Ù Å©´Ù¸é Sendbuffer overflow¿¡ Á÷¸éÇÏ°Ô µÉ °ÍÀÌ´Ù. mpeg °°Àº ¸î¹é¸Å°¡ ÆÄÀϵµ ¹«³È÷ Àü¼ÛÇØ ÁÙ ¼ö ÀÖ¾î¾ß ÇÒÅÙµ¥ ÇöÀç ±îÁöÀÇ ÀÛ¾÷À¸·Î´Â ¹æ¹ýÀÌ ¸¶¶¥Âú´Ù. °í¹ÎÀ» Á» Çغ¸¸é,
- ¿©À¯¹öÆÛ»çÀÌÁî > ÆÄÀÏ»çÀÌÁî : Çѹø¿¡ ´Ù ¹Ð¾î ³Ö°í Á¾°á.
- 1)¿¡ ÇØ´çµÇÁö ¾ÊÀ» °æ¿ì, ÆÄÀϼ¾µåÅ¥¿¡ ³Ö°í
- ?OnIdle ¿¡¼, ÆÄÀϼ¾µåÅ¥°¡ ¹«¾ð°¡ ÀÖÀ¸¸é Àü¼Û
ÀÌ ¹æ¹ýÀ¸·Î ÇÒ ¶§¿¡´Â, ÆÄÀÏ Àü¼ÛµµÁß¿¡ ´Ù¸¥ ¼¾µå¸¦ ÇÒ ¼ö ¾ø´Ù - µ¥ÀÌÅÍ ¼ø¼°¡ ²¿Àδ٠-. ¿©·¯°³ÀÇ ÆÄÀÏÀ» ÇϳªÀÇ ¼ÒÄÏÀ¸·Î º¸³»·Á°í ÇÒ¶§¿¡µµ °³¼±µÇ¾îÁ®¾ß ÇÑ´Ù. ¾î·°Å³ª ¹®Á¦°¡ ¸¹´Ù. ÀÏ´Ü, 1)¹øÀ» ±¸ÇöÇØ º»´Ù.
Çѹø¿¡ ´Ù Àоî Àü¼Û
#define READ_ONCE 20000
int THttpClient::ResponseBody(const char *filename)
{
FILE *fp;
fp = fopen(filename, "r");
if(fp == NULL) return -1;
char buf[READ_ONCE];
int nread;
while(!feof(fp)){
nread = fread(buf, 1, READ_ONCE, fp);
if(nread < 1) break;
if(sendbuf->Push(nread, buf) < 1){
// buffer overflow
break;
}
}
fclose(fp);
return 1;
}
±âÁ¸
?T
EpollSocket<
?TEpollClient> ¿¡¼ ÇÑ °¡Áö ¹®Á¦°¡ ÀÖ¾ú´Âµ¥, ¼¹öÂÊÀÇ Àǵµ·Î ¿¬°áÀ» ²÷À» ¹æ¹ýÀÌ ¸¶¶¥ÂúÀº °ÍÀÌ´Ù. HTTP ÇÁ·ÎÅäÄÝÀÇ ±¸Çö¿¡¼ ¿øÇÏ´Â ¹®¼¸¦ ´Ù Àü¼ÛÇÏ°í ³ª¸é, ¼¹ö´Â ¿¬°áÀ» ²÷µµ·Ï µÇ¾î ÀÖ´Ù. ¹®Á¦´Â
?SendBuffer¿¡ µ¥ÀÌÅÍ°¡ ³²¾ÆÀÖ´Â »óȲ¿¡¼´Â ÀÌ µ¥ÀÌÅ͸¦ ´Ù Àü¼ÛÇÏ°í Á¾·áÇØ¾ß Çϴµ¥, ±âÁ¸ÀÇ ±¸Á¶¿¡¼´Â
?OnIdle¿¡¼ ¿¡·¯¸¦ ¸®ÅÏÇؼ
?T
EpollSocket.Idle()¿¡¼ Á¾·á󸮿¡ µé¾î°¡µµ·Ï ÇØÁÖ°í, º°µµÀÇ Á¾·áó¸® ÇÁ·Î½ÃÀú¸¦ ¸¸µé¾î¼ ¹öÆÛ¸¦ ºñ¿öÁÖ°í ¹öÆÛ°¡ ´Ù ºñ¿öÁö¸é ¿¬°áÀ» Á¾·áÇϵµ·Ï ÀÛ¼ºÇØ¾ß Çß´Ù.
ÀÌ ¹®Á¦¸¦ ÇØ°áÇϱâ À§ÇØ,
?TEpollClient´Â is_readyto_close() ÇÔ¼ö¸¦ ÀÛ¼ºÇϵµ·Ï
°¿äÇÏ°í, ¹öÆÛ°¡ ºñ¿öÁ³À» °æ¿ì¿¡¸¸ true¸¦ ¸®ÅÏÇϵµ·Ï Çß´Ù (¹°·Ð read, write¿¡¼ ¿¡·¯°¡ ¹ß»ýÇ߰ųª disconnectµÈ °æ¿ì´Â ÀÌ °æ¿ì¸¦ °Ë»çÇÒ ÇÊ¿ä°¡ ¾ø´Ù).
?T
EpollSocket¿¡¼´Â
?OnIdle¿¡¼ °¢ ¿¬°áÀÇ is_readyto_close¸¦ °Ë»çÇؼ, ¸¸¾à true°¡ µ¹¾Æ¿À¸é ¿¬°áÁ¾·á󸮸¦ ÇÑ´Ù (ÀÌ¹Ì ¹öÆÛ´Â ´Ù ºñ¿öÁ®ÀÖ´Ù!).
?TEpollClientÀÇ ¼öÁ¤
class TEpollClient
{
....
virtual bool is_readyto_close(void) = NULL;
....
};
?TEpollSocketÀÇ ¼öÁ¤
// map <int, T *> ¶ó°í ¾²°í½ÍÁö¸¸ ¾Æ·¡Ã³·³ ½áÁà¾ß warningÀÌ ³ªÁö ¾Ê´Â´Ù.
typedef std::_Rb_tree_iterator<std::pair<const int, T*>, std::pair<const int, T*>&, std::pair<const int, T*>*> mapit;
template <typename T>
int TEpollSocket<T>::Idle(void)
{
mapit it = mapClient.begin();
while(it != mapClient.end()){
it ->second->OnIdle();
if(it->second->is_readyto_close()) return OnDisconnect(it);
it++;
}
return mapClient.size();
}
template <typename T>
int TEpollSocket<T>::OnDisconnect(mapit& it)
{
T *tmpClient = it -> second;
if(! tmpClient) return -1;
mapClient.erase(it);
epoll->Delete(it->first);
close(it->first);
delete tmpClient;
return mapClient.size();
}
?THttpClientÀÇ ¼öÁ¤
class THttpClient : public TTextClient
{
protected :
bool is_force_close;
....
public :
THttpClient(const int lfd, const char *laddr) : TTextClient(lfd, laddr)
{
is_force_close = false;
};
....
virtual bool is_readyto_close(void);
....
};
bool THttpClient::is_readyto_close(void)
{
if(! is_force_close) return false;
if(! sendbuf->empty()) return false;
return true;
}
´Ù µÆ´Ù!! ÀÌÁ¦ º¸³¾¸¸Å º¸³ÂÀ¸¸é, is_force_close = true·Î ÇØÁÖ¸é µÈ´Ù.
int THttpClient::msgGET(const char *url)
{
....
if(...){
....
ResponseHeader(httpcode, fileinfo.st_mtime, fileinfo.st_size, mime);
ResponseBody(filename);
}
is_force_close = true;
....
1.6 Signal Çڵ鷯 #
ÇÁ·Î±×·¥ÀÌ for(;;) ÀÇ ¹«ÇÑ·çÇÁ¸¦ °è¼Ó µ¹±â¶§¹®¿¡ Á¤»óÀûÀÎ Á¾·á󸮸¦ ¸øÇÏ°í Ctrl-C ¸¦ ´·¯¼ ³¡³»¾ß Çϴµ¥, SIGTERM°ú SIGINT¿¡ ´ëÇÑ Çڵ鷯¸¦ ¸¸µé¾î ºÙ¿© º¸¾Ò´Ù.