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; }