epoll_wait被signal信号中断时的处理

#include
#include 

#include

#include "util/vl_netutil.h"


using namespace std;


using namespace SNL;

#define DEL_CLOSE(mapOffset,iEpollFD,iCurFD,ev) epoll_ctl( iEpollFD, EPOLL_CTL_DEL, iCurFD, &ev );\
       close( iCurFD ); mapOffset.erase( mapOffset.find( iCurFD ) ); 

     


     
void ctrl_c_op( int signo )
{
    cout << "caught SIGUSR1, no : " << signo   << endl;
}


int main( int argc, char** argv )
{

 string sLocalIP;
 
 int iRet = getLocalAddr(  sLocalIP  );
 
 if ( iRet != 0  ||  sLocalIP.empty()  )
 {
  cout << "getLocalAddr fail, return : iRet : " << iRet  << endl;
  
  return -1;
 }
 
 unsigned short iPort = atoi( argv[1] );

 int iListenFD = socket( AF_INET, SOCK_STREAM, 0 );
 
 if ( iListenFD ==  INVALID_SOCKET )
 { 
  cout << "create socket failed! error : " << strerror( errno )  << endl;
  
  return -2;
 }
 
 iRet = setBlock( iListenFD, false );
 
 if ( iRet < 0 )
 {
  return -1;
 }
 
 int iFlag = 1;
 
 int iLen = sizeof ( iFlag );
 
 if ( setsockopt(  iListenFD, SOL_SOCKET,
   SO_REUSEADDR, &iFlag, iLen ) == -1 ) 
    {
        cout << "setsocketopt REUSEADDR  failed! error : " << strerror( errno )  << endl;
  
  return -2;
    }

 struct sockaddr_in sa;
 
 /* clear the memory */
 
 size_t iAddrLen = sizeof ( struct sockaddr_in );
  
 
 memset( &sa, 0, iAddrLen  );
 
 /* initialize structure */
 
 sa.sin_family = AF_INET;
 
 sa.sin_port = htons( iPort );
 
 sa.sin_addr.s_addr = inet_addr( sLocalIP.c_str()  );
 
 if ( bind( iListenFD, (struct sockaddr *)&sa, sizeof ( sa ) ) < 0 )
 {
  cout << "bind socket failed! error : " << strerror( errno )  << endl;
  
  return -3;
 }
 
 if ( listen(  iListenFD,  220 ) < 0  )
 {
  cout << "listen socket failed! error : " << strerror( errno )  << endl;
  
  return -4;
 }
 

 
 int iEpollSize = 10000;
 
 int iEpollFD =  epoll_create(  iEpollSize + 1   );
 
 epoll_event ev  ;
 
 epoll_event * events = new epoll_event [ iEpollSize + 1 ];
 
  ev.data.fd = iListenFD;
  
     //设置要处理的事件类型
  
     ev.events = EPOLLIN | EPOLLET;
  
     //注册epoll事件
  
     epoll_ctl( iEpollFD, EPOLL_CTL_ADD, iListenFD, &ev );

  
 int iListenFDNum = -1;
  
 int iConnFD = -1;
 
 struct sockaddr_in  clientAddr;
 
 /* clear the memory */
 
 memset( &clientAddr, 0,   iAddrLen  );
 
 
 string sOpenFile = "./data.log";
 
 
 struct stat  stStat;
 
 iRet = stat( sOpenFile.c_str() , &stStat );
 
 if ( iRet != 0 )
 {
  cout << "stat file "  << sOpenFile << " fail!  error :  " 
   <<   strerror( errno )  << endl;
  
  return -1;
 }
 
 
 // file related
 
 int iFileFD = open( sOpenFile.c_str()  , O_RDONLY  )  ;
 
 if ( iFileFD < 0 )
 {
  cout << "open file "  << sOpenFile << " fail!  error :  " 
   <<   strerror( errno )  << endl;
  
  return -1;
 }

 
 size_t iFileSize = stStat.st_size;
 
 int iSendSize = iFileSize;
 
 int iCurFD = -1;
 
 off_t iCurOffset = 0;
 
 map< int,  size_t  > mapOffset;
 
 int i = 0;
 
 int iMaxSendCount = 1000000;
 
 int iCurSendCount = 0;
 
 size_t iClientPort = 0;
 
 char sClientIP [ INET_ADDRSTRLEN ] = { 0 };
 
 
  struct sigaction act;
   
    act.sa_handler=ctrl_c_op;
 
    sigemptyset(&act.sa_mask);
 
    act.sa_flags=0;
 
    iRet = sigaction( SIGUSR1,&act,NULL ) ;
 
 if ( iRet != 0 )
 {
  cout << "sigaction failed ! iRet : " << iRet  << endl;
  
  return -1;
 }
 
 cout <<  "sigaction succ " << endl;
 
 
 
 for ( ; ; ) // unstoppable loop 
 {
  do
  {
  
   iListenFDNum  = epoll_wait( iEpollFD, events, iEpollSize + 1 , -1 );
   
   if ( iListenFDNum  == -1  && errno == EINTR  )
   {
    cout << "epoll_wait return -1 and EINTR "  << endl;
    
   }
   
  } while ( iListenFDNum  == -1  && errno == EINTR  );
  
  if ( iListenFDNum   == -1   && errno != EINTR  )
  {
   cout << "epoll_wait  return : " << iListenFDNum << ", errmsg : " 
    << strerror( errno ) << endl;
    
   break;
  }
  
  // iListenFDNum > 0 
  
   for ( i = 0; i <  iListenFDNum; ++i )
   {
                
                if ( events[i].data.fd ==  iListenFD ) // listen fd, just accept 
                {                              
     
     for ( ; ; ) // loop accept to EAGAIN 
     {
      iConnFD  = accept( iListenFD, (sockaddr *)(&clientAddr), & iAddrLen );
      
      if ( iConnFD  < 0  )
      {
       if ( errno  == EAGAIN  || errno == EWOULDBLOCK )
       {
        cout << "listen fd got EAGAIN" << endl;
        
        break;
       }
       
       cout << "accept socket failed! error : " << strerror( errno )  << endl;
       
       return -5;
       
      }     
      
      char * p = inet_ntoa(  clientAddr.sin_addr  );
      
      memcpy( sClientIP, p,  strlen( p ) ); 
      
      iClientPort = ntohs( clientAddr.sin_port );
      
      cout <<  "accept  one connect, set to nonblock :  "
       << sClientIP << " : " << iClientPort   << endl;
     
      iRet = setBlock( iConnFD, false );
      
      if ( iRet != 0 ) // set to block fail, just continue
      {
       close( iConnFD );
       
       cout << "set ConnFD non block failed! iRet : " << iRet   << endl;
       
       //continue to accept
        
      }
      else // accept succ , add to epoll and  wait for it 
      {
      
       cout << "add " << iConnFD 
        << " to epoll, EPOLLOUT  |  EPOLLIN  | EPOLLET "  << endl;
     
       //设置用于读操作的文件描述符

       ev.data.fd = iConnFD;

       //设置用于注测的读操作事件
       
       ev.events = EPOLLOUT | EPOLLIN | EPOLLET;
       

       //注册ev

       epoll_ctl( iEpollFD, EPOLL_CTL_ADD,iConnFD, &ev );
      
      }
     
     }
     
     
     //再次注册 listen fd 的  in事件
     
     ev.data.fd = iListenFD;
      
      //设置要处理的事件类型
      
     ev.events = EPOLLIN | EPOLLET;
      
      //注册epoll事件
      
     epoll_ctl( iEpollFD, EPOLL_CTL_MOD, iListenFD, &ev );
     
     // continue to listen for accept

    }
    else // ConnFD , just sendfile 
    {    
     iCurFD = events[i].data.fd;
     
     if (    events[i].events & EPOLLOUT    )
     {
      if ( mapOffset.find( iCurFD ) ==  mapOffset.end()  )
      {
       mapOffset[ iCurFD ] = 0;
      }
      
      iCurOffset = mapOffset[ iCurFD ];
      
      iSendSize = iFileSize -  iCurOffset;
      
      do
      {
       iRet = sendfile( iCurFD,  iFileFD,    &iCurOffset,  iSendSize  ) ;
      
      }  while ( iRet == -1 && errno == EINTR );
     
      if ( iRet  < 0  )
      {
       if ( errno == EAGAIN )
       {
        cout <<  "sendfile got EAGAIN , just continue" << endl;
        
        continue;
       }
       
       //other error, just close and del it
       
       cout << " sendfile return -1 and error is : " << strerror( errno )   << endl;

       DEL_CLOSE( mapOffset, iEpollFD, iCurFD, ev );
       
       continue;
       
      }
      else if ( iRet == 0 )
      {
       cout <<  "sendfile return 0 , just close and del it " << endl;
       
       DEL_CLOSE( mapOffset,  iEpollFD, iCurFD, ev );
       
       continue;
      }
      
      cout <<  "succ send  " << iRet << " bytes : "  << endl;
      
      mapOffset[ iCurFD ] += iRet;
            
      if (  mapOffset[ iCurFD ]  >= iFileSize  )
      {
       cout <<  "sendfile all, succ send one file : " << iCurFD   
        << ", size : " << mapOffset[ iCurFD ]  << endl;
       
       DEL_CLOSE( mapOffset,  iEpollFD, iCurFD, ev );
       
       ++iCurSendCount;
       
       if ( iCurSendCount >= iMaxSendCount )
       {
        cout <<  "max send count reach, just exit. " 
         << iCurSendCount  << endl;
        
        goto EXIT;
       }
       
       continue;
      }
      
      
      
      //设置用于读操作的文件描述符

      ev.data.fd = iCurFD;

      //设置用于注测的读操作事件
       
      ev.events = EPOLLOUT | EPOLLIN | EPOLLET;

      //注册ev

      epoll_ctl( iEpollFD, EPOLL_CTL_MOD, iCurFD, &ev );

      // continue to listen for EPOLLOUT
     }
     else // other EPOLL events ,just take as wrong ,close and continue
     {
      if (    events[i].events & EPOLLIN    ) // client close socket 
      {
       cout << "client close socket,just del it. "  << endl;
      }
      else
      {
       cout << "error : Conn FD fail or sth.  not EPOLLOUT "  << endl;
      }
      
      DEL_CLOSE( mapOffset,  iEpollFD, iCurFD, ev );
     }
    }
   }
 }
 
 
EXIT:

 epoll_ctl( iEpollFD, EPOLL_CTL_DEL, iListenFD, &ev ); 
 
 close( iEpollFD );
 
 close ( iListenFD );
 
 close ( iFileFD );
 
 delete []events;
 
 return 0;
}

 

$ ./MyPatchServer 10070
sigaction succ

 

当另开一个窗口strace 这个进程的ip时,这里会中断返回-1,打印下面的这行:
epoll_wait return -1 and EINTR

再另开一个窗口,向这个进程发送SIGUSR1信号时,输出下面的内容:

caught SIGUSR1, no : 10
epoll_wait return -1 and EINTR

由此我们得出结论:

当安装了信号处理函数时,如果进程收到了信号,会首先调用信号处理函数,信号处理

完成后返回时,epoll_wait返回-1,错误码置位EINTR

你可能感兴趣的:(网络编程)