FrontPage|FindPage|TitleIndex|RecentChanges|RSS Epoll Socket2
 

¹öÆÛ¸µÀ» Àû¿ëÇÑ ?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); 

  1. ¼ö½ÅµÈ µ¥ÀÌÅÍ°¡ countº¸´Ù ¸¹À¸¸é, count¸¸Å­ Àаí(count¿Í °°Àº°ª ¸®ÅÏ) ÀÐÁö ¾ÊÀº ³ª¸ÓÁö µ¥ÀÌÅÍ´Â ¿î¿µÃ¼Á¦ ¹öÆÛ¿¡ ³²¾ÆÀÖ°Ô µÈ´Ù.
  2. ¼ö½ÅµÈ µ¥ÀÌÅÍ°¡ countº¸´Ù °°°Å³ª ÀÛÀ¸¸é, µ¥ÀÌÅÍ»çÀÌÁŭ ÀÐ°í ±× »çÀÌÁ ¸®ÅÏÇÑ´Ù.
  3. ¼ö½ÅµÈ µ¥ÀÌÅÍ°¡ ¾øÀ¸¸é, ¿¡·¯(-1)¸¦ ¸®ÅÏÇÏ°í errno == EAGAIN ÀÌ µÈ´Ù (nonblocking À¸·Î ¸¸µé¾î³ù±â¶§¹®ÀÌ´Ù. ¸¸¾à blocking socketÀ̶ó¸é ¿©±â¼­ µ¥ÀÌÅÍ°¡ µé¿Ã¶§±îÁö ÇÁ·Î±×·¥ÀÌ ¸ØÃá´Ù --);
  4. 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 µ¿ÀÛ Á¤¸® #

¿©Å±îÁö¸¦ ´ë·« Á¤¸®Çغ¸¸é,

  1. ?OnRead¿¡¼­´Â µ¥ÀÌÅ͸¦ Àо ?RecvBuffer¿¡ ´ã´Â´Ù.
  2. ?OnWrite¿¡¼­´Â WOULDBLOCK flag¸¦ ¼ÂÇÑ´Ù.
  3. ³²´Â½Ã°£¿¡(?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°¡ ÇÑ°è¿´´Ù.

1.9 ¼Ò½º #


Replace original file
Rename if it already exist
File nameSize(byte)Date
 .. 2007-01-09
echo2.tgz306392004-06-29
Total 1 files
Password:

last modified 2004-06-29 16:10:02
EditText|FindPage|DeletePage|LikePages|UploadedFiles|UploadFile|