#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