epoll實例(Linux)

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章