epoll 實例練習
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const unsigned char PACKET_FLAGS_ZLIB = 0x1;
const unsigned int BUFSIZE = 1024 * 96;
const unsigned int PH_LEN = sizeof (unsigned int) + sizeof (unsigned char);
const unsigned int PACKET_ZIP_MIN =32;
const unsigned char PACKET_FLAGS_ZIP = 0x02;
const unsigned int MAX_DATASIZE = BUFSIZE - 1 - PH_LEN;
const unsigned int LISTEN_MAX = 2000;
const unsigned int EVENTS_MAX = 256;
bool bfinal = false;
#define gettid() syscall(SYS_gettid)
#define geterror() printf("%s:%d tid:%d error:%s\n", __FUNCTION__, __LINE__, gettid(), strerror(errno))
/*
#define TEMP_FAILURE_RETRY(expression) \
(__extension__\
({ long int __result;\
do __result = (long int)(expression);\
while(__result == -1L&& errno == EINTR);\
__result;})\
#endif
*/
void setnonblocking(int sock)
{
int opts;
opts = fcntl(sock,F_GETFL);
if (opts < 0)
{
perror("fcntl(sock,GETFL)");
exit(1);
}
opts = opts|O_NONBLOCK;
if (fcntl(sock, F_SETFL, opts) < 0)
{
perror("fcntl(sock,SETFL,opts)");
exit(1);
}
}
void ctrlcHandler(int signum)
{
bfinal = true;
}
void hupHandler(int signum)
{
}
void setSigaction()
{
struct sigaction sig;
sig.sa_handler = ctrlcHandler;
//sigemptyset(&sig.sa_mask);
sigaction(SIGUSR1, &sig, NULL);
sig.sa_flags = 0;
sigaction(SIGINT, &sig, NULL);
sigaction(SIGQUIT, &sig, NULL);
sigaction(SIGABRT, &sig, NULL);
sigaction(SIGTERM, &sig, NULL);
sig.sa_handler = hupHandler;
sigaction(SIGHUP, &sig, NULL);
sig.sa_handler = SIG_IGN;
///在寫到管道時讀進程終止,則產生該信號,
///當類型爲SOCK_STREAM的套接字不再連接時,進程寫到該套接字產生該信號,忽略該信號,否則一旦客戶端失去連接,程序就退出。
sigaction(SIGPIPE, &sig, NULL);
}
int main(int argc, char* argv[])
{
//後臺運行
//daemon(1, 0);
//設置信號處理
setSigaction();
std::map mapSock;
unsigned char sendBuf[BUFSIZE];
unsigned char recvBuf[BUFSIZE];
unsigned int recvLen;
int sockfd; //監聽fd
struct sockaddr_in servaddr;
char bind_host[20];
memset(bind_host, 0, sizeof(bind_host));
memset(&servaddr, 0, sizeof(servaddr));
sprintf(bind_host, "%s", "127.0.0.1");
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(22222);
/*
if( -1 == inet_addr("255.255.255.255") )
cout<<"error"< 0 )
{
setnonblocking(sockcoon);
//ev.events = EPOLLIN | EPOLLOUT | EPOLLET;
ev.events = EPOLLIN | EPOLLERR | EPOLLPRI | EPOLLET;
ev.data.fd = sockcoon;
int error_num = 0;
if (-1 == ( error_num = epoll_ctl(epfd, EPOLL_CTL_ADD, sockcoon, &ev) ) )
{
printf("test: add %d | error:%d\n", sockcoon, error_num);
close(sockcoon);
perror("epoll_ctl: add error"); //連接套接字
}
mapSock[sockcoon] = sockcoon;
printf("connect success sock:%d\n", sockcoon);
}
}
else if( events[i].events & (EPOLLERR|EPOLLPRI) )
{
if (events[i].events & EPOLLERR)
{
int error = 0;
socklen_t errlen = sizeof( error );
if ( getsockopt( events[i].data.fd, SOL_SOCKET, SO_ERROR, ( void* )&error, &errlen) )
printf("%s:%d, pid:%d,tid=%d: epoll error: %d\n", __PRETTY_FUNCTION__, __LINE__, getpid(), gettid(), error);
printf("%s:%d, pid:%d,tid=%d: connection error\n", __PRETTY_FUNCTION__, __LINE__, getpid(), gettid());
mapSock.erase(events[i].data.fd);
if (-1 == epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, &ev) )
{
printf("%s:%s\n", __FUNCTION__,strerror(errno));
}
shutdown(events[i].data.fd, SHUT_RDWR);
close(events[i].data.fd);
events[i].data.fd = -1;
}
else
{
printf("%s:%d, pid:%d,tid=%d: connection error:get out-of-band data\n", __PRETTY_FUNCTION__, __LINE__, getpid(), gettid());
mapSock.erase(events[i].data.fd);
if (-1 == epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, &ev) )
{
printf("%s:%d %s\n", __FUNCTION__, __LINE__, strerror(errno));
}
shutdown(events[i].data.fd, SHUT_RDWR);
close(events[i].data.fd);
events[i].data.fd = -1;
}
}
else if( events[i].events & EPOLLIN ) //如果是已經連接的用戶,並且收到數據,那麼進行讀入。
{
int n = 0;
int read = 0;
/// linux下當連接斷開,還發數據的時候,會向系統發送一個異常消息,如果不作處理,系統會出BrokePipe,程序會退出。
/// 爲此,函數的最後一個參數設置MSG_NOSIGNAL,禁止向系統發送異常消息。
n = TEMP_FAILURE_RETRY(::recv(usesock, recvBuf+read, BUFSIZE, MSG_NOSIGNAL));
/// 非阻塞下 收到EAGAIN 或EWOULDBLOCK,表明套接口沒有數據讀寫,或者收到其他新號的中斷
if( -1 == n && (errno == EAGAIN || errno == EWOULDBLOCK) )
{
}
else if( 0 == n )
{
//對端關閉
mapSock.erase(events[i].data.fd);
if (-1 == epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, &ev))
{
printf("%s:%d %s\n", __FUNCTION__, __LINE__, strerror(errno));
}
shutdown(events[i].data.fd, SHUT_RDWR);
close(usesock);
events[i].data.fd = -1;
printf("%s:%d, tid=%d: recv EOF: n = 0\n", __PRETTY_FUNCTION__, __LINE__, gettid() );
geterror();
}
else
{
//success recv
//每個sock都應該有接收隊列,這裏只是測試
printf("success recv len:%d:%s\n", n, recvBuf);
memset(recvBuf, 0, sizeof(recvBuf));
}
}
else if( events[i].events & EPOLLOUT ) //如果是已經連接的用戶,並且有數據發送,那麼進行寫入。
{
int n = 0;
int sendLen = 0;
if( sendLen = strlen((char *)sendBuf) < BUFSIZE )
sendBuf[sendLen+1] = sendLen%10;
n = TEMP_FAILURE_RETRY(::send(usesock, sendBuf, sendLen+2, MSG_NOSIGNAL));
if( -1 == n && (errno == EAGAIN || errno == EWOULDBLOCK) )
{
}
else if( n > 0 )
{
printf("send success len:%d:%s\n", n, sendBuf);
if( n > 200 )
memset(sendBuf, 0, sizeof(sendBuf));
}
}
}
}
for(std::map::iterator itr = mapSock.begin(); itr != mapSock.end(); ++itr)
{
if( itr->second )
{
printf("close fd :%d \n", itr->second);
if (-1 == epoll_ctl(epfd, EPOLL_CTL_DEL, itr->second, &ev))
{
//printf("%s:%d %s\n", __FUNCTION__, __LINE__, strerror(errno));
geterror();
}
shutdown(itr->second, SHUT_RDWR);
close(itr->second);
}
}
close(sockfd);
close(epfd);
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main()
{
int sockfd = 0;
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if( sockfd <= 0 )
return -1;
socklen_t len = 0;
struct sockaddr_in servaddr;
char bind_host[20];
memset(bind_host, 0, sizeof(bind_host));
memset(&servaddr, 0, sizeof(servaddr));
sprintf(bind_host, "%s", "127.0.0.1");
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(22222);
if( inet_pton(AF_INET, bind_host, &servaddr.sin_addr) <= 0 ){
printf("inet_pton error for %s\n", bind_host);
exit(0);
}
if( connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0 )
{
printf("connect error\n");
close(sockfd);
return -2;
}
int n = 0;
for(int i= 100; i< 200; i+=20)
{
char buff[100];
sprintf(buff, "%d", i);
while( (n = send(sockfd, buff, sizeof(buff), MSG_NOSIGNAL)) < 0 )
{
}
printf("send len :%d\n", n);
}
sleep(10);
shutdown(sockfd, SHUT_RDWR);
close(sockfd);
return 0;
}