¹öÆÛ¸µÀ» Àû¿ëÇÑ ?TEpollSocket °³¼± #
¾ö¹ÐÈ÷ ¸»Çϸé,
EpollSocketÀ» °³¼±ÇÏ´Â °ÍÀÌ ¾Æ´Ï°í
?TClient¸¦ °³¼±ÇÏ´Â °Í. À̸§µµ ¹Ù²ã¼
?TBasicClient ¶ó°í ÇÏ°Ú´Ù. ¹°·Ð »ç¿ëÀÚ´Â À̹ø ÀÛ¾÷À» ÅëÇؼ ¹öÆÛ¸µ¿¡ ´ëÇؼ ½Å°æ¾²Áö ¾Ê¾Æµµ µÉ °ÍÀÌ°í, µ¥ÀÌÅ͸¦ ¼Û½Å & ¼ö½ÅÇÏ´Â °Í±îÁö ½Å°æ¾²Áö ¾Ê¾Æµµ µÈ´Ù.
- 1 ¹öÆÛ¸µÀ» Àû¿ëÇÑ ?TEpollSocket °³¼±
- 1.1 ¿ø·¡ÀÇ ?TClient
- 1.2 °³¼±ÇÏ·Á´Â ?TBasicClient
- 1.3 ?OnRead()ÀÇ ±¸Çö
- 1.4 ¿î¿µÃ¼Á¦ ¼ÒÄϹöÆÛ Á¶Á¤
- 1.5 ?OnWrite() ±¸Çö
- 1.6 Flush() ±¸Çö
- 1.7 ?TBasicClient µ¿ÀÛ Á¤¸®
- 1.8 ±âŸ ±¸Çö
- 1.9 ¼Ò½º
1.1 ¿ø·¡ÀÇ ?TClient #
#include "epsocket.h"
class TClient : public TEpollClient
{
public :
TClient(const int lfd, const char *laddr) : TEpollClient(lfd, laddr)
{
// Ãʱâȶ§ Ãß°¡ÀûÀ¸·Î ÇØÁÖ°í½ÍÀº ÀϵéÀÌ ÀÖ´Ù¸é ¿©±â¿¡ ...
};
virtual int OnRead(void);
virtual int OnWrite(void);
virtual int OnError(const int nerror);
};
1.2 °³¼±ÇÏ·Á´Â ?TBasicClient #
#include "epsocket.h"
#include "buffer.h"
#define MAX_BUF (128 * 1024) // 128K
class TBasicClient : public TEpollClient
{
protected :
TBinQueue *sendbuf, *recvbuf;
bool is_would_block;
bool is_error;
public :
TBasicClient(const int lfd, const char *laddr) : TEpollClient(lfd, laddr)
{
// Ãʱâȶ§ Ãß°¡ÀûÀ¸·Î ÇØÁÖ°í½ÍÀº ÀϵéÀÌ ÀÖ´Ù¸é ¿©±â¿¡ ...
is_would_block = false;
is_error = false;
sendbuf = new TBinQueue(MAX_BUF);
recvbuf = new TBinQueue(MAX_BUF);
};
~TBasicClient()
{
delete sendbuf;
delete recvbuf;
};
virtual int OnRead(void);
virtual int OnWrite(void);
virtual int OnError(const int nerror);
virtual int OnIdle(void);
};
?TBinQueueÀÇ ¹öÆÛ·Î sendbuf, recvbuf µÎ°³¸¦ °¡Áö°í ÀÖ°í 128KÀÇ Å©±â¸¦ °¡Áöµµ·Ï ÇÏ¿´´Ù. ¹öÆÛ´Â ¸» ±×´ë·Î ÀϽÃÀûÀÎ ¿ÏÃæÀÇ ¸ñÀûÀ̹ǷΠÀÛ°Ô Àâ°Å³ª Å©°Ô Àâ°Å³ª Å« Àǹ̴ ¾ø´Ù. ´Ù¸¸ ÀϽÃÀûÀÎ ¼¹öºÎÇÏ (¿¹¸¦ µé¾î µð½ºÅ© ÀÔÃâ·Â)¸¦ °¨´çÇÒ ¸¸ÅÀÇ ¿ÏÃ濵¿ªÀ» °¡Áö°í ÀÖ¾î¾ß ÇϹǷÎ, ÃæºÐÈ÷ Àâ¾ÆÁÖ´Â°Ô ÁÁ´Ù. ÇϳªÀÇ Ä¿³Ø¼ÇÀº 128K ¾¿ÀÇ µÎ°³¹öÆÛ¸¦ °¡Áö°ÔµÇ´Âµ¥ (256K), µ¿½ÃÁ¢¼Ó 1õÀ̸é 256MBÀÇ ¸Þ¸ð¸®¸¦ Â÷ÁöÇÏ°Ô µÈ´Ù. 1¸¸À» Ä¿¹öÇÏ·Á¸é 2.5GÀÇ ¹öÆ۸޸𸮰¡ ÇÊ¿äÇÏ´Ï -_-; ÀÌ ¼ýÀÚ¸¦ ÁÙÀÌ´ø°¡ ¸Þ¸ð¸®¸¦ ¸¹ÀÌ »ç´ø°¡ Ç϶ó!
µ¿½ÃÁ¢¼ÓÀÌ 10 À̳»ÀÎ ´Ù°èÃþ ¼¹ö (Áï, ÀÌ¿ëÀÚ Á¢¼ÓÀº Agent°¡ ¹Þ°í °ÔÀÓ¼¹ö¿Í ä³Î Çϳª·Î Åë½ÅÇÑ´Ù´ø°¡ ÇÏ´Â...)¶ó¸é Ä¿³Ø¼Ç¼ýÀÚº¸´Ù´Â Ä¿³Ø¼Ç´ç Àü¼Û·®ÀÌ ´õ Å« Àǹ̰¡ ÀÖÀ¸¹Ç·Î ÀÌ ¹öÆÛ¸¦ 10M ÀÌ»óÀ¸·Î ÀâÀ» ¼öµµ ÀÖ´Ù.
¹öÆÛ»çÀÌÁ »ç¿ëÀÚ°¡ Á¤ÇÏ°Ô Çϵµ·Ï ÀÎÅÍÆäÀ̽º¸¦ ¼öÁ¤Çغ¸¾Ò´Ù. constructor´Â epsocketÀÌ È£ÃâÇϱ⶧¹®¿¡ °£Á¢Àû ±¸ÇöÀ» Çߴµ¥, ³»ºÎÀûÀ¸·Î ¹öÆÛ»çÀÌÁ ¸®ÅÏÇØÁÖ´Â ÇÔ¼ö¸¦ ÀÛ¼ºÇÏ°í, »ç¿ëÀÚ°¡ ÀçÁ¤ÀÇ ÇÒ ¼ö ÀÖµµ·Ï ÇÑ´Ù. µðÆúÆ®·Î´Â 128K ¹öÆÛ¸¦ »ý¼ºÇϵµ·Ï ÇÑ´Ù.
protected :
virtual int internalbuffersize(void) = { return MAX_BUF; };
...
public :
TBasicClient(...)
{
...
int maxbuf = internalbuffersize();
sendbuf = new TBinQueue(maxbuf);
recvbuf = new TBinQueue(maxbuf);
};
~TBasicClient()
{
delete sendbuf;
delete recvbuf;
};
...
1.3 ?OnRead()ÀÇ ±¸Çö #
int TBasicClient::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(recvbuf->Push(nread, buf) < 1) return EP_ERROR_READ_OVERFLOW;
nin += nread;
return EP_ERROR_NONE;
};
read À̺¥Æ®°¡ ¹ß»ýÇßÀ»¶§, Áï ¾î¶² µ¥ÀÌÅÍ°¡ ¼ö½ÅµÇ¾úÀ»¶§
ÀúÀý·Î È£ÃâµÇ´Â Çڵ鷯ÀÇ ±¸ÇöÀÌ´Ù. SIZE_OSBUF »ó¼ö´Â setsockopt(..., SO_RCVBUF, ...) ¿¡¼ ÁöÁ¤ÇØÁØ °ª°ú °°°Ô Çϱâ À§ÇØ »ç¿ëµÈ´Ù. readÀÇ ¼¼¹ø° ÆĶó¹ÌÅÍ count¿¡ ´ëÇؼ°¡ ¾à°£ ¾Ö¸Å¸ðÈ£ÇÑ ±¸¼®ÀÌ Àִµ¥,
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
- ¼ö½ÅµÈ µ¥ÀÌÅÍ°¡ countº¸´Ù ¸¹À¸¸é, count¸¸Å Àаí(count¿Í °°Àº°ª ¸®ÅÏ) ÀÐÁö ¾ÊÀº ³ª¸ÓÁö µ¥ÀÌÅÍ´Â ¿î¿µÃ¼Á¦ ¹öÆÛ¿¡ ³²¾ÆÀÖ°Ô µÈ´Ù.
- ¼ö½ÅµÈ µ¥ÀÌÅÍ°¡ countº¸´Ù °°°Å³ª ÀÛÀ¸¸é, µ¥ÀÌÅÍ»çÀÌÁŠÀÐ°í ±× »çÀÌÁ ¸®ÅÏÇÑ´Ù.
- ¼ö½ÅµÈ µ¥ÀÌÅÍ°¡ ¾øÀ¸¸é, ¿¡·¯(-1)¸¦ ¸®ÅÏÇÏ°í errno == EAGAIN ÀÌ µÈ´Ù (nonblocking À¸·Î ¸¸µé¾î³ù±â¶§¹®ÀÌ´Ù. ¸¸¾à blocking socketÀ̶ó¸é ¿©±â¼ µ¥ÀÌÅÍ°¡ µé¿Ã¶§±îÁö ÇÁ·Î±×·¥ÀÌ ¸ØÃá´Ù --);
- countÀÇ °ªÀº unistd.h ¿¡ ÁöÁ¤µÈ SSIZE_MAX º¸´Ù ÀÛ¾Æ¾ß ÇÑ´Ù. (Å©°Ô ÁöÁ¤µÉ °æ¿ì´Â ¾î¶»°Ô µÉÁö ¸ð¸¥´Ù --; )
ÀÌ·± ÀÌÀ¯·Î ¾Ö¸Å¸ðÈ£ÇÔÀ» ¾ø¾Ö±â À§Çؼ, ÃÖ´ë·Î Àо¾ß ÇÏ´Â °ª°ú ¿î¿µÃ¼Á¦¼ÒÄϹöÆÛ »çÀÌÁ °°°Ô ÇÑ´Ù. ±×·¯¸é Àû¾îµµ ¿î¿µÃ¼Á¦ ¹öÆÛ¿¡ µ¥ÀÌÅÍ°¡ ³²´Â ÀÏÀº ¾ø°Ô µÈ´Ù.
1.4 ¿î¿µÃ¼Á¦ ¼ÒÄϹöÆÛ Á¶Á¤ #
#define SIZE_OSBUF 8192
int send_buf = SIZE_OSBUF;
int recv_buf = SIZE_OSBUF;
setsockopt(fd, IPPROTO_TCP, SO_SNDBUF, (char *)&send_buf, sizeof(send_buf));
setsockopt(fd, IPPROTO_TCP, SO_RCVBUF, (char *)&recv_buf, sizeof(recv_buf));
8K·Î Çߴµ¥, ÇÁ·Î±×·¥ÀÌ ÀÚÁÖµ¥ÀÌÅ͸¦ ¸¸µé¾î³»°í ÀÚÁÖ ºñ¿ì´Â °æ¿ì¶ó¸é ´õ ÀÛ°ÔÇصµ »ó°ü¾øÁö¸¸ Çѹø¿¡ ¸¹Àº µ¥ÀÌÅ͸¦ ½î°í ¹Þ°í ÇÏ´Â °æ¿ì¿¡´Â ´õ Å©°Ô ÇØÁÖ´Â°Ô ÁÁ´Ù. ¿Â¶óÀΰÔÀÓ¼¹öµéÀ̶ó¸é ´õ ÀÛ°Ô, ftp³ª http¼¹ö¶ó¸é ´õ Å©°Ô ÇÑ´Ù. ÇÏÁö¸¸ ±×³É 8K¸é ¿©·¯¸ñÀû¿¡ ¹«¹æÇÒ µíÇÏ´Ù.
1.5 ?OnWrite() ±¸Çö #
int TBasicClient::OnWrite(void)
{
is_would_block = false;
return Flush();
}
?OnWrite()°¡ È£ÃâµÇ¾ú´Ù´Â °ÍÀº ¼ÒÄÏÀÌ ¾²±â°¡´ÉÇÏ´Ù´Â ÀǹÌÀε¥, 1) ¼ÒÄÏÀÌ Ã³À½ ¿¬°áµÇ¾úÀ»¶§ 2) WOULDBLOCK »óÅ°¡ ÇؼҵǾúÀ»¶§ 3) WOULDBLOCKÀÌ ¾Æ´Ñ »óÅ¿¡¼, µ¥ÀÌÅÍ°¡ ¼ö½ÅµÇ¾úÀ»¶§ÀÌ´Ù. À§ Äڵ忡¼´Â would_block flag¸¦ false·Î ²¨ÁÖ°í
?SendBuffer¸¦ Flush Çϵµ·Ï ÀÛ¼ºÇÏ¿´´Ù. ½ÇÁ¦·Î µ¥ÀÌÅÍ Àü¼ÛÀº Flush() ¿¡¼ ÇÏ°Ô µÈ´Ù.
1.6 Flush() ±¸Çö #
#define SIZE_APACKET 1400
class TBasicClient : public TEpollClient
{
public :
int Flush(void);
....
};
....
int TBasicClient::Flush(void)
{
if(is_error) return EP_ERROR;
char buf[SIZE_APACKET];
int nsize;
while(! is_would_block){
if(sendbuf->empty()) return EP_ERROR_NONE;
nsize = sendbuf->View(SIZE_APACKET, buf);
int nwrite = write(fd, buf, nsize);
if( nwrite != nsize ){
// ¹º°¡ ¿¡·¯°¡ »ý±ä°Í
if(nwrite < 1){
return OnError(EP_ERROR_WRITE_GEN);
}
is_would_block = true;
}
sendbuf->Skip(nwrite);
nout += nwrite;
}
return EP_ERROR_NONE;
}
?SendBuffer¸¦ ºñ¿ï¶§±îÁö write ÇÔ¼ö¸¦ È£ÃâÇÏ¿© ½ÇÁ¦ Àü¼ÛÀ» ÇÏ´Â ÇÔ¼öÀÌ´Ù. nin, nout º¯¼ö¸¦ µÎ¾î ¹Þ°í º¸³½ µ¥ÀÌÅ;çÀ» Áý°èÇϵµ·Ï Çß´Ù. Àü¼Û µµÁß¿¡ ¿¡·¯°¡ ¹ß»ýÇϰųª, WOULDBLOCK »óÅ°¡ µÇ¸é ¸ØÃá´Ù. write ÇÔ¼öÀÇ ¼¼¹ø° ÆĶó¹ÌÅÍ count´Â ½ÇÁ¦·Î º¸³»·Á°í ÇÏ´Â ¾çÀε¥, ÇÔ¼öÀÇ °á°ú°ªÀÌ count¿Í °°Áö ¾ÊÀº °æ¿ì´Â 1) ¿¡·¯°¡ ¹ß»ýÇ߰ųª( < 1 ), 2) WOULDBLOCK ÀÌ µÈ °æ¿ìÀÌ´Ù. ( nwrite < nsize) WOULDBLOCKÀÌ ¹ß»ýÇÑ°æ¿ì¿¡´Â ½ÇÁ¦º¸³½ »çÀÌÁî nwrite ¸¸Å¸¸ ¹öÆÛ¸¦ ºñ¿ì°í Flush ÇÔ¼ö¼öÇàÀ» ÁßÁöÇÑ´Ù.
´Ù º¸³»Áö ¸øÇÏ°í ³²Àº ºÎºÐÀº, ´ÙÀ½¹ø¿¡
?OnWrite °¡ È£ÃâµÇ¸é¼ ´Ù½Ã Flush ¸¦ ÅëÇؼ º¸³»°Ô µÈ´Ù. ¾Æ´Ï¸é ³²´Â ½Ã°£¿¡ Flush() È£ÃâÀ» ÇØÁØ´Ù (ÇÊÀÚ´Â ÀÌ ¹æ¹ýÀ» ¼±È£ÇÑ´Ù)
?OnError()ÀÇ ±¸Çö
int TBasicClient::OnError(const int nerror)
{
is_error = true;
return nerror;
}
Ưº°È÷ ÇÏ´Â ÀÏÀº ¾ø´Ù. --;
?OnIdle()ÀÇ ±¸Çö
int TBasicClient::OnIdle(void)
{
// µé¾î¿Â µ¥ÀÌÅÍ Ã³¸®
while(! recvbuf->empty()){
char buf[SIZE_APACKET];
int nsize = recvbuf->Pop(SIZE_APACKET, buf);
if(sendbuf->Push(nsize, buf) < 1){
// cout << "sendbuffer overflow\n";
}
}
// Flushing
Flush();
return ERROR_NONE;
}
?OnIdle˼,
?TEpollSocket¿¡¼ ¸ðµç ¿¬°á¿¡ ´ëÇØ È£ÃâÇÏ´Â ÇÔ¼ö (¾Æ·¡¿¡¼ ºÎ¿¬¼³¸í)·Î ¸ÞÀξ²·¹µå, ȤÀº ¸ÞÀÎÇÔ¼ö°¡ ±×³É °è¼ÓÇؼ È£ÃâÇØÁÖ´Â ÇÔ¼öÀÌ´Ù. µ¥ÀÌÅÍ ¼ö½Å&¼Û½ÅÀº ÀÚµ¿ÀûÀ¸·Î
?OnRead,
?OnWrite¿¡¼ ÇÏÁö¸¸ ¼ö½ÅµÈ µ¥ÀÌÅÍÀÇ ºÐ¼®&ó¸®(=¸Þ½ÃÁö ÇÁ·Î¼¼½Ì)´Â ÀÌ °÷¿¡¼ ÇÏ°í ÀÖ´Ù (Ä¿³Ø¼Ç³¢¸®ÀÇ »óȣĿ¹Â´ÏÄÉÀ̼ÇÀÌ ¸¹Àº äÆü¹ö¸¦ Á¦ÀÛÇÒ¶§¿¡´Â ÀÌ °÷¿¡¼ ÇÏÁö ¾Ê°í Ŭ·¡½º ¿ÜºÎ¿¡¼ ÇÒ °ÍÀÌ´Ù).
ÇÁ·Î±×·¥Àº,
?RecvBuffer¿¡¼ Àû´çÇÑ »çÀÌÁîÀÇ ÆÐŶÀ» ÀÐ¾î¼ Ã³¸® (echo¼¹öÀ̱⠶§¹®¿¡ ¹Ù·Î ´Ù½Ã ¹Ý¼Û)Çϵµ·Ï ÇÏ°í ÀÖ´Ù. ¹Ý¼ÛÀº ¹°·Ð Á÷Á¢ write ÄÝÀ» ÇÏÁö ¾Ê°í ´ÜÁö
?SendBuffer¿¡ ³Ö¾îÁֱ⸸ ÇÑ´Ù. ½ÇÁ¦ Àü¼ÛÀº
?OnWrite ¸¦ ÅëÇØ Flush°¡ ÇÒ °ÍÀÌ´Ù.
1.7 ?TBasicClient µ¿ÀÛ Á¤¸® #
¿©Å±îÁö¸¦ ´ë·« Á¤¸®Çغ¸¸é,
- ?OnRead¿¡¼´Â µ¥ÀÌÅ͸¦ ÀÐ¾î¼ ?RecvBuffer¿¡ ´ã´Â´Ù.
- ?OnWrite¿¡¼´Â WOULDBLOCK flag¸¦ ¼ÂÇÑ´Ù.
- ³²´Â½Ã°£¿¡(?OnIdle) µé¾î¿Âµ¥ÀÌÅÍÀÇ ºÐ¼®&ó¸®, ½ÇÁ¦ µ¥ÀÌÅÍÀÇ Àü¼ÛÀ» ÇÑ´Ù.
1.8 ±âŸ ±¸Çö #
?OnIdle ±¸Çö
?OnIdleÀÇ ±¸ÇöÀº, main °ú
?TEpollSocketÀÇ º¯°æÀ» ÇÊ¿ä·Î ÇÑ´Ù.
class TEpollSocket
{
....
public :
....
int Idle(void);
};
....
template <typename T>
int TEpollSocket<T>::Idle(void)
{
map<int, T *>::const_iterator it = mapClient.begin();
while(it != mapClient.end()){
it++ ->second->OnIdle();
}
return mapClient.size();
}
ÇÏ´Â ÀÏÀº Àüü ¿¬°á(Áï
?TBasicClientµé)ÀÇ IdleÀ» È£ÃâÇØÁÖ´Â ÀÏÀÌ´Ù. for_each()·Î ±¸ÇöÇÏ´Â °ÍÀÌ ¸ÚÁúÅÙµ¥ c++ ½Ç·ÂÀÌ µþ·Á¼ ÄÄÆÄÀϵǴ Äڵ带 ÀÛ¼ºÇϴµ¥ ½ÇÆÐÇß´Ù. °Ô´Ù°¡ À§ ÇÔ¼ö´Â Typename Implicity °æ°í°¡ ³ª¿Â´Ù. mapClient.begin() iteratorÀÇ Å¸ÀÔÀÌ ¹«¾ùÀÎÁöµµ Àß ¸ð¸£°Ú´Ù. --; ´©°¡ Á» °íÃÄÁÖ¼¼¿ä.
ÄÄÆÄÀÏ·¯ °æ°í -_-;;
epsocket.h: In member function `int TEpollSocket<T>::Idle()':
epsocket.h:273: warning: `std::map<int, T*, std::less<int>,
std::allocator<std::pair<const int, T*> > >::const_iterator' is implicitly a typename
epsocket.h:273: warning: implicit typename is deprecated, please see the documentation for details
»ç½Ç ÀÌ·¸°Ô ÀÛ¼ºÇÏ°í ½ÍÁö¸¸... ´É·ÂÀÌ...
template <typename T>
int TEpollSocket<T>::Idle(void)
{
for_each(mapClient.begin(), mapClient.end(), mem_fun( ????? ::OnIdle));
}
main() º¯°æ
#define WANT_MAX_CLIENT 10000
int main(void)
{
int n, max_client;
struct rlimit rlim;
getrlimit(RLIMIT_NOFILE, &rlim);
rlim.rlim_cur = WANT_MAX_CLIENT;
setrlimit(RLIMIT_NOFILE, &rlim);
getrlimit(RLIMIT_NOFILE, &rlim);
max_client = rlim.rlim_cur;
cout << "MAX_NOFILE : " << max_client << endl;
TEpollSocket<TBasicClient> esock(max_client);
esock.Listen(8000);
for(;;){
esock.Do(10);
esock.Idle();
}
}
esock.Do ¿Í esock.IdleÀ» ¹«ÀÛÁ¤ È£ÃâÇÏ°í ÀÖ´Ù --; getrlimit¿Í setrlimit·Î ¿¸°ÆÄÀÏ°¹¼ö Á¶Á¤À» ÇÏ°í Àִµ¥, ÇÊÀÚ ½Ã½ºÅÛ¿¡¼ rootÀ¯Àú·Î´Â 32768±îÁö °¡´ÉÇÏÁö¸¸ ÀϹÝÀ¯Àú±ÇÇÑÀ¸·Î´Â 1024°¡ ÇÑ°è¿´´Ù.