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 <strings.h>
#include <string.h>
#include <stdio.h>

using namespace std;

#define MAXLINE 32
#define OPEN_MAX 100
#define LISTENQ 20
#define SERV_PORT 5555
#define INFTIM 1000



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

int main()
{
/*
  结构体epoll_event 被用于注册所感兴趣的事件和回传所发生待处理的事件,定义如下:

    typedef union epoll_data {
        void *ptr;
         int fd;
         __uint32_t u32;
         __uint64_t u64;
     } epoll_data_t;//保存触发事件的某个文件描述符相关的数据

     struct epoll_event {
         __uint32_t events;      // epoll event
         epoll_data_t data;      // User data variable
     };

    其中events表示感兴趣的事件和被触发的事件,可能的取值为:
    EPOLLIN :表示对应的文件描述符可以读;
    EPOLLOUT:表示对应的文件描述符可以写;
    EPOLLPRI: 表示对应的文件描述符有紧急的数可读;

    EPOLLERR:表示对应的文件描述符发生错误;
    EPOLLHUP:表示对应的文件描述符被挂断;
    EPOLLET:    ET的epoll工作模式;

*/

ssize_t n;
char line[MAXLINE];
socklen_t clilen;
struct epoll_event ev,events[20];
int i,maxi,listenfd,connfd,sockfd,epfd,nfds;
/*
1、epoll_create函数
     函数声明:int epoll_create(int size)
    功能:该函数生成一个epoll专用的文件描述符,其中的参数是指定生成描述符的最大范围;
*/
epfd = epoll_create(256);


struct sockaddr_in clientaddr;
struct sockaddr_in serveraddr;
listenfd = socket(AF_INET,SOCK_STREAM,0);

//设置非阻塞
setnonblocking(listenfd);
/*
2、epoll_ctl函数
     函数声明:int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
     功能:用于控制某个文件描述符上的事件,可以注册事件,修改事件,删除事件。
    @epfd:由 epoll_create 生成的epoll专用的文件描述符;
     @op:要进行的操作,EPOLL_CTL_ADD 注册、EPOLL_CTL_MOD 修改、EPOLL_CTL_DEL 删除;
     @fd:关联的文件描述符;
    @event:指向epoll_event的指针;
    成功:0;失败:-1
*/
ev.data.fd = listenfd;
ev.events = EPOLLIN | EPOLLET;
epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);

//服务器地址绑定
bzero(&serveraddr,sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = INADDR_ANY;
serveraddr.sin_port = htons(1234);
bind(listenfd,(const sockaddr*)&serveraddr,sizeof(serveraddr));
listen(listenfd,LISTENQ);

while(true) {
    /*
    3、epoll_wait函数
    函数声明:int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout)
    功能:该函数用于轮询I/O事件的发生;
    @epfd:由epoll_create 生成的epoll专用的文件描述符;
    @epoll_event:用于回传代处理事件的数组;
    @maxevents:每次能处理的事件数;
    @timeout:等待I/O事件发生的超时值;
    成功:返回发生的事件数;失败:-1
    */
    nfds = epoll_wait(epfd,events,20,500);
    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;
          }
          //设置非阻塞
          setnonblocking(listenfd);
          printf("ip client:%s\n",inet_ntoa(clientaddr.sin_addr));
          ev.data.fd = connfd;
          ev.events = EPOLLIN | EPOLLET;
          epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev);
        }else if (events[i].events & EPOLLIN) {//如果是已经连接的用户,并且收到数据,那么进行读入。

            if ((sockfd = events[i].data.fd) < 0) continue;//确定连接用户存在
            if ((n = read(sockfd,line,MAXLINE))< 0){
                if(errno == ECONNRESET) {
                    close(sockfd);
                    events[i].data.fd = -1;
                } else
                    cout<<"readline error"<<endl;
            }else if (0 == n){
                close(sockfd);
                events[i].data.fd = -1;
            }
            printf("Data ==:%s\n",line);
            ev.data.fd = sockfd;//修改sockfd事件为EPOLLOUT
            ev.events = EPOLLOUT | EPOLLET;
            epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);
        } else if (events[i].events & EPOLLOUT) {
            printf("send data to client\n");

            sockfd = events[i].data.fd;
            write(sockfd,"hello client",n);
            ev.data.fd =sockfd;
            ev.events = EPOLLIN | EPOLLET;
            epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);
        }
    }

}



return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值