epoll示例

书到用时方恨少,一切尽在不言中
#include <iostream>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

using namespace std;

#define MAXLINE 5
#define OPEN_MAX 100
#define LISTENQ 20
#define SERV_PORT 5000
#define INFTIM 1000

void setnonblocking(int sock)
{
    int opts;
    opts=fcntl(sock,F_GETFL);
    if(opts<0)
    {
        perror("fcntl(sock,GETFL)");
        return;
    }
    opts = opts|O_NONBLOCK;

    if(fcntl(sock,F_SETFL,opts)<0)
    {
        perror("fcntl(sock,SETFL,opts)");
        return;
    }
}

void CloseAndDisable(int sockid, epoll_event ee)
{
    close(sockid);
    ee.data.fd = -1;
}

ssize_t socket_send(int sockfd, const char* buffer, size_t buflen)
{
  ssize_t tmp;
  size_t total = buflen;
  const char *p = buffer;

  while(1)
  {
     tmp = send(sockfd, p, total, 0);
     if(tmp < 0)
     {
        if(errno == EINTR)
            return -1;

        if(errno == EAGAIN)
        {
           usleep(1000);
           continue;
        }
           return -1;
     }
    
     if((size_t)tmp == total)
         return buflen;
     total -= tmp;
     p += tmp;
   }
   return tmp;
}
int main()
{
    int i, maxi, listenfd, connfd, sockfd,epfd,nfds, portnumber;
    char line[MAXLINE*50];
    socklen_t clilen;
    portnumber = 5000;

    struct epoll_event ev,events[20];
    epfd=epoll_create(256);
    
    struct sockaddr_in clientaddr;
    struct sockaddr_in serveraddr;
    listenfd = socket(AF_INET, SOCK_STREAM, 0);

    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serveraddr.sin_port=htons(portnumber);

    bind(listenfd,(sockaddr *)&serveraddr, sizeof(serveraddr));
    listen(listenfd, LISTENQ);

    ev.data.fd=listenfd;
    ev.events=EPOLLIN|EPOLLET;

    epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);

    maxi = 0;

    int bOut = 0;
    for ( ; ; )
    {
        if (bOut == 1)
            break;
        nfds=epoll_wait(epfd,events,20,-1);
        //printf("wait %d returns\n",nfds);
        for(i=0;i<nfds;++i)
        {        
            if(events[i].data.fd==listenfd)//如果新监测到一个SOCKET用户连接到了绑定的SOCKET端口
            {
                connfd = accept(listenfd,(sockaddr *)&clientaddr, &clilen);
                if(connfd<0){
                    perror("connfd<0");
                    return (1);
                }
                

                char *str = inet_ntoa(clientaddr.sin_addr);
                cout << "accapt a connection from " << str << endl;
                setnonblocking(connfd);
                ev.data.fd=connfd;
                ev.events=EPOLLIN | EPOLLET;
                //注册ev
                epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev);
            }
            else if(events[i].events & EPOLLIN)
            {
                cout << "EPOLLIN" << endl;
                if ( (sockfd = events[i].data.fd) < 0)
                    continue;

                cout << "START READ" << endl;
                char * head = line;
                int recvNum = 0;
                int count = 0;
                bool bReadOk = false;
                while(1)
                {
                    recvNum = recv(sockfd, head+count, MAXLINE-1, 0);
                    if(recvNum < 0)
                    {
                        if(errno == EAGAIN)
                        {//已没数据 不阻塞等待
                            bReadOk = true;
                            break;
                        }
                        else if (errno == ECONNRESET)
                        {
                                CloseAndDisable(sockfd, events[i]);
                                cout << "counterpart send out RST\n";
                                break;
                         }
                        else if (errno == EINTR)
                        {//有数据但未读到断了,所以要接着读
                            continue;
                        }
                        else
                        {
                            CloseAndDisable(sockfd, events[i]);
                            cout << "unrecovable error\n";
                            break;
                        }
                   }
                   else if( recvNum == 0)
                   {
                        CloseAndDisable(sockfd, events[i]);
                        cout << "counterpart has shut off\n";
                        break;
                   }

                   count += recvNum;
                   if ( recvNum == MAXLINE-1)
                   {
                   cout << "sleeping..."<<endl;
           sleep(5);
                       cout << "recvNum == MAXLINE-1\n"<<endl;
                       continue;
                   }
                   else // 0 < recvNum < MAXLINE-1
                   {
                       cout << "0 < recvNum < MAXLINE-1"<<endl;
                       bReadOk = true;
                       break; // 退出while(1),表示已经全部读完数据
                   }

                }

                if (bReadOk == true)
                {
                    line[count] = '\0';
                    cout << "we have read from the client : " << line;
                    ev.data.fd=sockfd;
                    ev.events = EPOLLOUT | EPOLLET;
                    epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);
                }
            }
            else if(events[i].events & EPOLLOUT) // 如果有数据发送
            {
                cout << "EPOLLOUT" << endl;
                const char str[] = "1234567890";
        //printf("%d\n",sizeof(str));
                memcpy(line, str, sizeof(str));
                //cout << line << endl;
        printf("d %d u %u lu %lu\n",i,i,i);
                sockfd = events[i].data.fd;
                int bWritten = 0;
                int writenLen = 0;
                int count = 0;
                char * head = line;
        bWritten=socket_send(sockfd,head,strlen(head));
                if (bWritten == strlen(head))
                {
                    ev.data.fd=sockfd;
                    ev.events=EPOLLIN | EPOLLET;
                    epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);
                }
            }
        }
    }
    return 0;
}

关于epoll和accept的注意点,参见http://www.ccvita.com/515.html

posted @ 2014-09-29 16:59  aitao  阅读(533)  评论(0编辑  收藏  举报